/ bytecode / UnlinkedCodeBlockGenerator.h
UnlinkedCodeBlockGenerator.h
  1  /*
  2   * Copyright (C) 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  
 27  #pragma once
 28  
 29  #include "UnlinkedCodeBlock.h"
 30  #include <wtf/Vector.h>
 31  
 32  namespace JSC {
 33  
 34  // FIXME: Create UnlinkedCodeBlock inside UnlinkedCodeBlockGenerator.
 35  // https://bugs.webkit.org/show_bug.cgi?id=207212
 36  class UnlinkedCodeBlockGenerator {
 37      WTF_MAKE_FAST_ALLOCATED;
 38      WTF_MAKE_NONCOPYABLE(UnlinkedCodeBlockGenerator)
 39  public:
 40      UnlinkedCodeBlockGenerator(VM& vm, UnlinkedCodeBlock* codeBlock)
 41          : m_vm(vm)
 42          , m_codeBlock(vm, codeBlock)
 43      {
 44      }
 45  
 46      VM& vm() { return m_vm; }
 47  
 48      bool isConstructor() const { return m_codeBlock->isConstructor(); }
 49      ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); }
 50      SuperBinding superBinding() const { return m_codeBlock->superBinding(); }
 51      JSParserScriptMode scriptMode() const { return m_codeBlock->scriptMode(); }
 52      NeedsClassFieldInitializer needsClassFieldInitializer() const { return m_codeBlock->needsClassFieldInitializer(); }
 53      bool usesEval() const { return m_codeBlock->usesEval(); }
 54      SourceParseMode parseMode() const { return m_codeBlock->parseMode(); }
 55      bool isArrowFunction() { return m_codeBlock->isArrowFunction(); }
 56      DerivedContextType derivedContextType() const { return m_codeBlock->derivedContextType(); }
 57      EvalContextType evalContextType() const { return m_codeBlock->evalContextType(); }
 58      bool isArrowFunctionContext() const { return m_codeBlock->isArrowFunctionContext(); }
 59      bool isClassContext() const { return m_codeBlock->isClassContext(); }
 60      unsigned numCalleeLocals() const { return m_codeBlock->m_numCalleeLocals; }
 61      unsigned numVars() const { return m_codeBlock->m_numVars; }
 62      unsigned numParameters() const { return m_codeBlock->numParameters(); }
 63      VirtualRegister thisRegister() const { return m_codeBlock->thisRegister(); }
 64      VirtualRegister scopeRegister() const { return m_codeBlock->scopeRegister(); }
 65      bool wasCompiledWithDebuggingOpcodes() const { return m_codeBlock->wasCompiledWithDebuggingOpcodes(); }
 66      bool hasCheckpoints() const { return m_codeBlock->hasCheckpoints(); }
 67      bool hasTailCalls() const { return m_codeBlock->hasTailCalls(); }
 68  
 69      // Updating UnlinkedCodeBlock.
 70      void setHasCheckpoints() { m_codeBlock->setHasCheckpoints(); }
 71      void setHasTailCalls() { m_codeBlock->setHasTailCalls(); }
 72      void setNumCalleeLocals(unsigned numCalleeLocals) { m_codeBlock->m_numCalleeLocals = numCalleeLocals; }
 73      void setNumVars(unsigned numVars) { m_codeBlock->m_numVars = numVars; }
 74      void setThisRegister(VirtualRegister thisRegister) { m_codeBlock->setThisRegister(thisRegister); }
 75      void setScopeRegister(VirtualRegister thisRegister) { m_codeBlock->setScopeRegister(thisRegister); }
 76      void setNumParameters(unsigned newValue) { m_codeBlock->setNumParameters(newValue); }
 77  
 78      UnlinkedMetadataTable& metadata() { return m_codeBlock->metadata(); }
 79      void addExpressionInfo(unsigned instructionOffset, int divot, int startOffset, int endOffset, unsigned line, unsigned column);
 80      void addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot);
 81      void addOpProfileControlFlowBytecodeOffset(InstructionStream::Offset offset)
 82      {
 83          m_opProfileControlFlowBytecodeOffsets.append(offset);
 84      }
 85  
 86      size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
 87      void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); }
 88      unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
 89      unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
 90  
 91      size_t numberOfSwitchJumpTables() const { return m_switchJumpTables.size(); }
 92      UnlinkedSimpleJumpTable& addSwitchJumpTable() { m_switchJumpTables.append(UnlinkedSimpleJumpTable()); return m_switchJumpTables.last(); }
 93      UnlinkedSimpleJumpTable& switchJumpTable(int tableIndex) { return m_switchJumpTables[tableIndex]; }
 94  
 95      size_t numberOfStringSwitchJumpTables() const { return m_stringSwitchJumpTables.size(); }
 96      UnlinkedStringJumpTable& addStringSwitchJumpTable() { m_stringSwitchJumpTables.append(UnlinkedStringJumpTable()); return m_stringSwitchJumpTables.last(); }
 97      UnlinkedStringJumpTable& stringSwitchJumpTable(int tableIndex) { return m_stringSwitchJumpTables[tableIndex]; }
 98  
 99      size_t numberOfExceptionHandlers() const { return m_exceptionHandlers.size(); }
100      UnlinkedHandlerInfo& exceptionHandler(int index) { return m_exceptionHandlers[index]; }
101      void addExceptionHandler(const UnlinkedHandlerInfo& handler) { m_exceptionHandlers.append(handler); }
102      UnlinkedHandlerInfo* handlerForBytecodeIndex(BytecodeIndex, RequiredHandler = RequiredHandler::AnyHandler);
103      UnlinkedHandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler);
104  
105      BitVector& bitVector(size_t i) { return m_bitVectors[i]; }
106      unsigned addBitVector(BitVector&& bitVector)
107      {
108          m_bitVectors.append(WTFMove(bitVector));
109          return m_bitVectors.size() - 1;
110      }
111  
112      unsigned numberOfConstantIdentifierSets() const { return m_constantIdentifierSets.size(); }
113      const Vector<ConstantIdentifierSetEntry>& constantIdentifierSets() { return m_constantIdentifierSets; }
114      void addSetConstant(IdentifierSet& set)
115      {
116          ASSERT(m_vm.heap.isDeferred());
117          unsigned result = m_constantRegisters.size();
118          m_constantRegisters.append(WriteBarrier<Unknown>());
119          m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
120          m_constantIdentifierSets.append(ConstantIdentifierSetEntry(set, result));
121      }
122  
123      const WriteBarrier<Unknown>& constantRegister(VirtualRegister reg) const { return m_constantRegisters[reg.toConstantIndex()]; }
124      const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
125      ALWAYS_INLINE JSValue getConstant(VirtualRegister reg) const { return m_constantRegisters[reg.toConstantIndex()].get(); }
126      const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
127  
128      unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
129      {
130          ASSERT(m_vm.heap.isDeferred());
131          unsigned result = m_constantRegisters.size();
132          m_constantRegisters.append(WriteBarrier<Unknown>());
133          m_constantRegisters.last().setWithoutWriteBarrier(v);
134          m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation);
135          return result;
136      }
137      unsigned addConstant(LinkTimeConstant linkTimeConstant)
138      {
139          ASSERT(m_vm.heap.isDeferred());
140          unsigned result = m_constantRegisters.size();
141          m_constantRegisters.append(WriteBarrier<Unknown>());
142          m_constantRegisters.last().setWithoutWriteBarrier(jsNumber(static_cast<int32_t>(linkTimeConstant)));
143          m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::LinkTimeConstant);
144          return result;
145      }
146  
147      unsigned addFunctionDecl(UnlinkedFunctionExecutable* n)
148      {
149          ASSERT(m_vm.heap.isDeferred());
150          unsigned size = m_functionDecls.size();
151          m_functionDecls.append(WriteBarrier<UnlinkedFunctionExecutable>());
152          m_functionDecls.last().setWithoutWriteBarrier(n);
153          return size;
154      }
155  
156      unsigned addFunctionExpr(UnlinkedFunctionExecutable* n)
157      {
158          unsigned size = m_functionExprs.size();
159          m_functionExprs.append(WriteBarrier<UnlinkedFunctionExecutable>());
160          m_functionExprs.last().setWithoutWriteBarrier(n);
161          return size;
162      }
163  
164      size_t numberOfIdentifiers() const { return m_identifiers.size(); }
165      const Identifier& identifier(int index) const { return m_identifiers[index]; }
166      void addIdentifier(const Identifier& i) { return m_identifiers.append(i); }
167  
168      using OutOfLineJumpTargets = HashMap<InstructionStream::Offset, int>;
169      void addOutOfLineJumpTarget(InstructionStream::Offset, int target);
170      int outOfLineJumpOffset(InstructionStream::Offset);
171      int outOfLineJumpOffset(const InstructionStream::Ref& instruction)
172      {
173          return outOfLineJumpOffset(instruction.offset());
174      }
175      OutOfLineJumpTargets replaceOutOfLineJumpTargets()
176      {
177          OutOfLineJumpTargets newJumpTargets;
178          std::swap(m_outOfLineJumpTargets, newJumpTargets);
179          return newJumpTargets;
180      }
181  
182      size_t metadataSizeInBytes() { return m_codeBlock->metadataSizeInBytes(); }
183  
184      void getLineAndColumn(const ExpressionRangeInfo&, unsigned& line, unsigned& column) const;
185  
186      void applyModification(BytecodeRewriter&, InstructionStreamWriter&);
187  
188      void finalize(std::unique_ptr<InstructionStream>);
189  
190      void dump(PrintStream&) const;
191  
192  private:
193      VM& m_vm;
194      Strong<UnlinkedCodeBlock> m_codeBlock;
195      // In non-RareData.
196      Vector<InstructionStream::Offset> m_jumpTargets;
197      Vector<Identifier> m_identifiers;
198      Vector<WriteBarrier<Unknown>> m_constantRegisters;
199      Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
200      Vector<WriteBarrier<UnlinkedFunctionExecutable>> m_functionDecls;
201      Vector<WriteBarrier<UnlinkedFunctionExecutable>> m_functionExprs;
202      Vector<ExpressionRangeInfo> m_expressionInfo;
203      OutOfLineJumpTargets m_outOfLineJumpTargets;
204      // In RareData.
205      Vector<UnlinkedHandlerInfo> m_exceptionHandlers;
206      Vector<UnlinkedSimpleJumpTable> m_switchJumpTables;
207      Vector<UnlinkedStringJumpTable> m_stringSwitchJumpTables;
208      Vector<ExpressionRangeInfo::FatPosition> m_expressionInfoFatPositions;
209      HashMap<unsigned, UnlinkedCodeBlock::RareData::TypeProfilerExpressionRange> m_typeProfilerInfoMap;
210      Vector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets;
211      Vector<BitVector> m_bitVectors;
212      Vector<ConstantIdentifierSetEntry> m_constantIdentifierSets;
213  };
214  
215  } // namespace JSC