/ bytecode / UnlinkedCodeBlock.h
UnlinkedCodeBlock.h
  1  /*
  2   * Copyright (C) 2012-2019 Apple Inc. All Rights Reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24   */
 25  
 26  #pragma once
 27  
 28  #include "BytecodeConventions.h"
 29  #include "CodeType.h"
 30  #include "DFGExitProfile.h"
 31  #include "ExpressionRangeInfo.h"
 32  #include "HandlerInfo.h"
 33  #include "Identifier.h"
 34  #include "InstructionStream.h"
 35  #include "JSCast.h"
 36  #include "LockDuringMarking.h"
 37  #include "Opcode.h"
 38  #include "ParserModes.h"
 39  #include "RegExp.h"
 40  #include "UnlinkedFunctionExecutable.h"
 41  #include "UnlinkedMetadataTable.h"
 42  #include "VirtualRegister.h"
 43  #include <algorithm>
 44  #include <wtf/BitVector.h>
 45  #include <wtf/HashSet.h>
 46  #include <wtf/RefCountedArray.h>
 47  #include <wtf/TriState.h>
 48  #include <wtf/Vector.h>
 49  #include <wtf/text/UniquedStringImpl.h>
 50  
 51  namespace JSC {
 52  
 53  class BytecodeLivenessAnalysis;
 54  class BytecodeRewriter;
 55  class CodeBlock;
 56  class Debugger;
 57  class FunctionExecutable;
 58  class ParserError;
 59  class ScriptExecutable;
 60  class SourceCode;
 61  class SourceProvider;
 62  class UnlinkedCodeBlock;
 63  class UnlinkedCodeBlockGenerator;
 64  class UnlinkedFunctionCodeBlock;
 65  class UnlinkedFunctionExecutable;
 66  struct ExecutableInfo;
 67  enum class LinkTimeConstant : int32_t;
 68  
 69  template<typename CodeBlockType>
 70  class CachedCodeBlock;
 71  
 72  typedef unsigned UnlinkedValueProfile;
 73  typedef unsigned UnlinkedArrayProfile;
 74  typedef unsigned UnlinkedArrayAllocationProfile;
 75  typedef unsigned UnlinkedObjectAllocationProfile;
 76  typedef unsigned UnlinkedLLIntCallLinkInfo;
 77  using ConstantIdentifierSetEntry = std::pair<IdentifierSet, unsigned>;
 78  
 79  struct UnlinkedStringJumpTable {
 80      struct OffsetLocation {
 81          int32_t branchOffset;
 82      };
 83  
 84      typedef HashMap<RefPtr<StringImpl>, OffsetLocation> StringOffsetTable;
 85      StringOffsetTable offsetTable;
 86  
 87      inline int32_t offsetForValue(StringImpl* value, int32_t defaultOffset)
 88      {
 89          StringOffsetTable::const_iterator end = offsetTable.end();
 90          StringOffsetTable::const_iterator loc = offsetTable.find(value);
 91          if (loc == end)
 92              return defaultOffset;
 93          return loc->value.branchOffset;
 94      }
 95  
 96  };
 97  
 98  struct UnlinkedSimpleJumpTable {
 99      RefCountedArray<int32_t> branchOffsets;
100      int32_t min;
101  
102      int32_t offsetForValue(int32_t value, int32_t defaultOffset);
103      void add(int32_t key, int32_t offset)
104      {
105          if (!branchOffsets[key])
106              branchOffsets[key] = offset;
107      }
108  };
109  
110  class UnlinkedCodeBlock : public JSCell {
111  public:
112      typedef JSCell Base;
113      static constexpr unsigned StructureFlags = Base::StructureFlags;
114  
115      static constexpr bool needsDestruction = true;
116  
117      template<typename, SubspaceAccess>
118      static void subspaceFor(VM&)
119      {
120          RELEASE_ASSERT_NOT_REACHED();
121      }
122  
123      enum { CallFunction, ApplyFunction };
124  
125      bool isConstructor() const { return m_isConstructor; }
126      bool usesEval() const { return m_usesEval; }
127      SourceParseMode parseMode() const { return m_parseMode; }
128      bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
129      DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
130      EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); }
131      bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
132      bool isClassContext() const { return m_isClassContext; }
133      bool hasTailCalls() const { return m_hasTailCalls; }
134      void setHasTailCalls() { m_hasTailCalls = true; }
135      bool allowDirectEvalCache() const { return !(m_features & NoEvalCacheFeature); }
136  
137      bool hasExpressionInfo() { return m_expressionInfo.size(); }
138      const RefCountedArray<ExpressionRangeInfo>& expressionInfo() { return m_expressionInfo; }
139  
140      bool hasCheckpoints() const { return m_hasCheckpoints; }
141      void setHasCheckpoints() { m_hasCheckpoints = true; }
142  
143      // Special registers
144      void setThisRegister(VirtualRegister thisRegister) { m_thisRegister = thisRegister; }
145      void setScopeRegister(VirtualRegister scopeRegister) { m_scopeRegister = scopeRegister; }
146  
147      // Parameter information
148      void setNumParameters(int newValue) { m_numParameters = newValue; }
149      unsigned numParameters() const { return m_numParameters; }
150  
151      // Constant Pools
152  
153      size_t numberOfIdentifiers() const { return m_identifiers.size(); }
154      const Identifier& identifier(int index) const { return m_identifiers[index]; }
155      const RefCountedArray<Identifier>& identifiers() const { return m_identifiers; }
156  
157      BitVector& bitVector(size_t i) { ASSERT(m_rareData); return m_rareData->m_bitVectors[i]; }
158  
159      const RefCountedArray<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
160      const WriteBarrier<Unknown>& constantRegister(VirtualRegister reg) const { return m_constantRegisters[reg.toConstantIndex()]; }
161      ALWAYS_INLINE JSValue getConstant(VirtualRegister reg) const { return m_constantRegisters[reg.toConstantIndex()].get(); }
162      const RefCountedArray<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
163  
164      unsigned numberOfConstantIdentifierSets() const { return m_rareData ? m_rareData->m_constantIdentifierSets.size() : 0; }
165      const RefCountedArray<ConstantIdentifierSetEntry>& constantIdentifierSets() { ASSERT(m_rareData); return m_rareData->m_constantIdentifierSets; }
166  
167      // Jumps
168      size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
169      unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
170      unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
171  
172      UnlinkedHandlerInfo* handlerForBytecodeIndex(BytecodeIndex, RequiredHandler = RequiredHandler::AnyHandler);
173      UnlinkedHandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler);
174  
175      bool isBuiltinFunction() const { return m_isBuiltinFunction; }
176  
177      ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
178      SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
179      JSParserScriptMode scriptMode() const { return static_cast<JSParserScriptMode>(m_scriptMode); }
180  
181      const InstructionStream& instructions() const;
182  
183      unsigned numCalleeLocals() const { return m_numCalleeLocals; }
184      unsigned numVars() const { return m_numVars; }
185  
186      // Jump Tables
187  
188      size_t numberOfSwitchJumpTables() const { return m_rareData ? m_rareData->m_switchJumpTables.size() : 0; }
189      UnlinkedSimpleJumpTable& switchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_switchJumpTables[tableIndex]; }
190  
191      size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; }
192      UnlinkedStringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
193  
194      UnlinkedFunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
195      size_t numberOfFunctionDecls() { return m_functionDecls.size(); }
196      UnlinkedFunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); }
197      size_t numberOfFunctionExprs() { return m_functionExprs.size(); }
198  
199      // Exception handling support
200      size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; }
201      UnlinkedHandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
202  
203      CodeType codeType() const { return static_cast<CodeType>(m_codeType); }
204  
205      VirtualRegister thisRegister() const { return m_thisRegister; }
206      VirtualRegister scopeRegister() const { return m_scopeRegister; }
207  
208      bool hasRareData() const { return m_rareData.get(); }
209  
210      int lineNumberForBytecodeIndex(BytecodeIndex);
211  
212      void expressionRangeForBytecodeIndex(BytecodeIndex, int& divot,
213          int& startOffset, int& endOffset, unsigned& line, unsigned& column) const;
214  
215      bool typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot);
216  
217      void recordParse(CodeFeatures features, bool hasCapturedVariables, unsigned lineCount, unsigned endColumn)
218      {
219          m_features = features;
220          m_hasCapturedVariables = hasCapturedVariables;
221          m_lineCount = lineCount;
222          // For the UnlinkedCodeBlock, startColumn is always 0.
223          m_endColumn = endColumn;
224      }
225  
226      StringImpl* sourceURLDirective() const { return m_sourceURLDirective.get(); }
227      StringImpl* sourceMappingURLDirective() const { return m_sourceMappingURLDirective.get(); }
228      void setSourceURLDirective(const String& sourceURL) { m_sourceURLDirective = sourceURL.impl(); }
229      void setSourceMappingURLDirective(const String& sourceMappingURL) { m_sourceMappingURLDirective = sourceMappingURL.impl(); }
230  
231      CodeFeatures codeFeatures() const { return m_features; }
232      bool hasCapturedVariables() const { return m_hasCapturedVariables; }
233      unsigned lineCount() const { return m_lineCount; }
234      ALWAYS_INLINE unsigned startColumn() const { return 0; }
235      unsigned endColumn() const { return m_endColumn; }
236  
237      const RefCountedArray<InstructionStream::Offset>& opProfileControlFlowBytecodeOffsets() const
238      {
239          ASSERT(m_rareData);
240          return m_rareData->m_opProfileControlFlowBytecodeOffsets;
241      }
242      bool hasOpProfileControlFlowBytecodeOffsets() const
243      {
244          return m_rareData && !m_rareData->m_opProfileControlFlowBytecodeOffsets.isEmpty();
245      }
246  
247      void dumpExpressionRangeInfo(); // For debugging purpose only.
248  
249      bool wasCompiledWithDebuggingOpcodes() const { return m_codeGenerationMode.contains(CodeGenerationMode::Debugger); }
250      bool wasCompiledWithTypeProfilerOpcodes() const { return m_codeGenerationMode.contains(CodeGenerationMode::TypeProfiler); }
251      bool wasCompiledWithControlFlowProfilerOpcodes() const { return m_codeGenerationMode.contains(CodeGenerationMode::ControlFlowProfiler); }
252      OptionSet<CodeGenerationMode> codeGenerationMode() const { return m_codeGenerationMode; }
253  
254      TriState didOptimize() const { return static_cast<TriState>(m_didOptimize); }
255      void setDidOptimize(TriState didOptimize) { m_didOptimize = static_cast<unsigned>(didOptimize); }
256  
257      static constexpr unsigned maxAge = 7;
258  
259      unsigned age() const { return m_age; }
260      void resetAge() { m_age = 0; }
261  
262      NeedsClassFieldInitializer needsClassFieldInitializer() const
263      {
264          if (m_rareData)
265              return static_cast<NeedsClassFieldInitializer>(m_rareData->m_needsClassFieldInitializer);
266          return NeedsClassFieldInitializer::No;
267      }
268  
269      void dump(PrintStream&) const;
270  
271      BytecodeLivenessAnalysis& livenessAnalysis(CodeBlock* codeBlock)
272      {
273          if (m_liveness)
274              return *m_liveness;
275          return livenessAnalysisSlow(codeBlock);
276      }
277  
278  #if ENABLE(DFG_JIT)
279      bool hasExitSite(const ConcurrentJSLocker& locker, const DFG::FrequentExitSite& site) const
280      {
281          return m_exitProfile.hasExitSite(locker, site);
282      }
283  
284      bool hasExitSite(const DFG::FrequentExitSite& site)
285      {
286          ConcurrentJSLocker locker(m_lock);
287          return hasExitSite(locker, site);
288      }
289  
290      DFG::ExitProfile& exitProfile() { return m_exitProfile; }
291  #endif
292  
293      UnlinkedMetadataTable& metadata() { return m_metadata.get(); }
294  
295      size_t metadataSizeInBytes()
296      {
297          return m_metadata->sizeInBytes();
298      }
299  
300  
301  protected:
302      UnlinkedCodeBlock(VM&, Structure*, CodeType, const ExecutableInfo&, OptionSet<CodeGenerationMode>);
303  
304      template<typename CodeBlockType>
305      UnlinkedCodeBlock(Decoder&, Structure*, const CachedCodeBlock<CodeBlockType>&);
306  
307      ~UnlinkedCodeBlock();
308  
309      void finishCreation(VM& vm)
310      {
311          Base::finishCreation(vm);
312      }
313  
314  private:
315      friend class BytecodeRewriter;
316      friend class UnlinkedCodeBlockGenerator;
317      template<typename Traits>
318      friend class BytecodeGeneratorBase;
319  
320      template<typename CodeBlockType>
321      friend class CachedCodeBlock;
322  
323      void createRareDataIfNecessary(const AbstractLocker&)
324      {
325          if (!m_rareData)
326              m_rareData = makeUnique<RareData>();
327      }
328  
329      void getLineAndColumn(const ExpressionRangeInfo&, unsigned& line, unsigned& column) const;
330      BytecodeLivenessAnalysis& livenessAnalysisSlow(CodeBlock*);
331  
332  
333      VirtualRegister m_thisRegister;
334      VirtualRegister m_scopeRegister;
335  
336      unsigned m_usesEval : 1;
337      unsigned m_isConstructor : 1;
338      unsigned m_hasCapturedVariables : 1;
339      unsigned m_isBuiltinFunction : 1;
340      unsigned m_superBinding : 1;
341      unsigned m_scriptMode: 1;
342      unsigned m_isArrowFunctionContext : 1;
343      unsigned m_isClassContext : 1;
344      unsigned m_hasTailCalls : 1;
345      unsigned m_constructorKind : 2;
346      unsigned m_derivedContextType : 2;
347      unsigned m_evalContextType : 2;
348      unsigned m_codeType : 2;
349      unsigned m_didOptimize : 2;
350      unsigned m_age : 3;
351      static_assert(((1U << 3) - 1) >= maxAge);
352      bool m_hasCheckpoints : 1;
353  public:
354      ConcurrentJSLock m_lock;
355  private:
356      CodeFeatures m_features { 0 };
357      SourceParseMode m_parseMode;
358      OptionSet<CodeGenerationMode> m_codeGenerationMode;
359  
360      unsigned m_lineCount { 0 };
361      unsigned m_endColumn { UINT_MAX };
362  
363      unsigned m_numVars { 0 };
364      unsigned m_numCalleeLocals { 0 };
365      unsigned m_numParameters { 0 };
366  
367      PackedRefPtr<StringImpl> m_sourceURLDirective;
368      PackedRefPtr<StringImpl> m_sourceMappingURLDirective;
369  
370      RefCountedArray<InstructionStream::Offset> m_jumpTargets;
371      Ref<UnlinkedMetadataTable> m_metadata;
372      std::unique_ptr<InstructionStream> m_instructions;
373      std::unique_ptr<BytecodeLivenessAnalysis> m_liveness;
374  
375  
376  #if ENABLE(DFG_JIT)
377      DFG::ExitProfile m_exitProfile;
378  #endif
379  
380      // Constant Pools
381      RefCountedArray<Identifier> m_identifiers;
382      RefCountedArray<WriteBarrier<Unknown>> m_constantRegisters;
383      RefCountedArray<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
384      using FunctionExpressionVector = RefCountedArray<WriteBarrier<UnlinkedFunctionExecutable>>;
385      FunctionExpressionVector m_functionDecls;
386      FunctionExpressionVector m_functionExprs;
387  
388  public:
389      struct RareData {
390          WTF_MAKE_STRUCT_FAST_ALLOCATED;
391  
392          RefCountedArray<UnlinkedHandlerInfo> m_exceptionHandlers;
393  
394          // Jump Tables
395          RefCountedArray<UnlinkedSimpleJumpTable> m_switchJumpTables;
396          RefCountedArray<UnlinkedStringJumpTable> m_stringSwitchJumpTables;
397  
398          RefCountedArray<ExpressionRangeInfo::FatPosition> m_expressionInfoFatPositions;
399  
400          struct TypeProfilerExpressionRange {
401              unsigned m_startDivot;
402              unsigned m_endDivot;
403          };
404          HashMap<unsigned, TypeProfilerExpressionRange> m_typeProfilerInfoMap;
405          RefCountedArray<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets;
406          RefCountedArray<BitVector> m_bitVectors;
407          RefCountedArray<ConstantIdentifierSetEntry> m_constantIdentifierSets;
408  
409          unsigned m_needsClassFieldInitializer : 1;
410      };
411  
412      int outOfLineJumpOffset(InstructionStream::Offset);
413      int outOfLineJumpOffset(const InstructionStream::Ref& instruction)
414      {
415          return outOfLineJumpOffset(instruction.offset());
416      }
417  
418  private:
419      using OutOfLineJumpTargets = HashMap<InstructionStream::Offset, int>;
420  
421      OutOfLineJumpTargets m_outOfLineJumpTargets;
422      std::unique_ptr<RareData> m_rareData;
423      RefCountedArray<ExpressionRangeInfo> m_expressionInfo;
424  
425  protected:
426      static void visitChildren(JSCell*, SlotVisitor&);
427      static size_t estimatedSize(JSCell*, VM&);
428  
429  public:
430      DECLARE_INFO;
431  };
432  
433  }