/ bytecode / UnlinkedFunctionExecutable.h
UnlinkedFunctionExecutable.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 "CodeSpecializationKind.h"
 29  #include "ConstructAbility.h"
 30  #include "ConstructorKind.h"
 31  #include "ExecutableInfo.h"
 32  #include "ExpressionRangeInfo.h"
 33  #include "Identifier.h"
 34  #include "Intrinsic.h"
 35  #include "JSCast.h"
 36  #include "ParserModes.h"
 37  #include "ParserTokens.h"
 38  #include "RegExp.h"
 39  #include "SourceCode.h"
 40  #include "VariableEnvironment.h"
 41  #include <wtf/Optional.h>
 42  
 43  namespace JSC {
 44  
 45  class Decoder;
 46  class FunctionMetadataNode;
 47  class FunctionExecutable;
 48  class ParserError;
 49  class SourceProvider;
 50  class UnlinkedFunctionCodeBlock;
 51  class CachedFunctionExecutable;
 52  
 53  enum UnlinkedFunctionKind {
 54      UnlinkedNormalFunction,
 55      UnlinkedBuiltinFunction,
 56  };
 57  
 58  class UnlinkedFunctionExecutable final : public JSCell {
 59  public:
 60      friend class CodeCache;
 61      friend class VM;
 62      friend class CachedFunctionExecutable;
 63  
 64      typedef JSCell Base;
 65      static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 66  
 67      template<typename CellType, SubspaceAccess>
 68      static IsoSubspace* subspaceFor(VM& vm)
 69      {
 70          return &vm.unlinkedFunctionExecutableSpace.space;
 71      }
 72  
 73      static UnlinkedFunctionExecutable* create(VM& vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, RefPtr<TDZEnvironmentLink> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor = false)
 74      {
 75          UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm.heap))
 76              UnlinkedFunctionExecutable(vm, vm.unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);
 77          instance->finishCreation(vm);
 78          return instance;
 79      }
 80  
 81      ~UnlinkedFunctionExecutable();
 82  
 83      const Identifier& name() const { return m_name; }
 84      const Identifier& ecmaName() const { return m_ecmaName; }
 85      void setEcmaName(const Identifier& name) { m_ecmaName = name; }
 86      unsigned parameterCount() const { return m_parameterCount; }; // Excluding 'this'!
 87      SourceParseMode parseMode() const { return static_cast<SourceParseMode>(m_sourceParseMode); };
 88  
 89      SourceCode classSource() const
 90      {
 91          if (m_rareData)
 92              return m_rareData->m_classSource;
 93          return SourceCode();
 94      }
 95      void setClassSource(const SourceCode& source)
 96      {
 97          ensureRareData().m_classSource = source;
 98      }
 99  
100      bool isInStrictContext() const { return m_isInStrictContext; }
101      FunctionMode functionMode() const { return static_cast<FunctionMode>(m_functionMode); }
102      ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
103      SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
104  
105      unsigned lineCount() const { return m_lineCount; }
106      unsigned linkedStartColumn(unsigned parentStartColumn) const { return m_unlinkedBodyStartColumn + (!m_firstLineOffset ? parentStartColumn : 1); }
107      unsigned linkedEndColumn(unsigned startColumn) const { return m_unlinkedBodyEndColumn + (!m_lineCount ? startColumn : 1); }
108  
109      unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; }
110      unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; }
111      unsigned unlinkedBodyEndColumn() const { return m_unlinkedBodyEndColumn; }
112      unsigned startOffset() const { return m_startOffset; }
113      unsigned sourceLength() { return m_sourceLength; }
114      unsigned parametersStartOffset() const { return m_parametersStartOffset; }
115      unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; }
116      unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
117      void setInvalidTypeProfilingOffsets();
118  
119      UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
120          VM&, const SourceCode&, CodeSpecializationKind, OptionSet<CodeGenerationMode>,
121          ParserError&, SourceParseMode);
122  
123      static UnlinkedFunctionExecutable* fromGlobalCode(
124          const Identifier&, JSGlobalObject*, const SourceCode&, JSObject*& exception, 
125          int overrideLineNumber, Optional<int> functionConstructorParametersEndPosition);
126  
127      SourceCode linkedSourceCode(const SourceCode&) const;
128      JS_EXPORT_PRIVATE FunctionExecutable* link(VM&, ScriptExecutable* topLevelExecutable, const SourceCode& parentSource, Optional<int> overrideLineNumber = WTF::nullopt, Intrinsic = NoIntrinsic, bool isInsideOrdinaryFunction = false);
129  
130      void clearCode(VM& vm)
131      {
132          m_unlinkedCodeBlockForCall.clear();
133          m_unlinkedCodeBlockForConstruct.clear();
134          vm.unlinkedFunctionExecutableSpace.set.remove(this);
135      }
136  
137      void recordParse(CodeFeatures features, bool hasCapturedVariables)
138      {
139          m_features = features;
140          m_hasCapturedVariables = hasCapturedVariables;
141      }
142  
143      CodeFeatures features() const { return m_features; }
144      bool hasCapturedVariables() const { return m_hasCapturedVariables; }
145  
146      static constexpr bool needsDestruction = true;
147      static void destroy(JSCell*);
148  
149      bool isBuiltinFunction() const { return m_isBuiltinFunction; }
150      ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
151      JSParserScriptMode scriptMode() const { return static_cast<JSParserScriptMode>(m_scriptMode); }
152      bool isClassConstructorFunction() const
153      {
154          switch (constructorKind()) {
155          case ConstructorKind::None:
156          case ConstructorKind::Naked:
157              return false;
158          case ConstructorKind::Base:
159          case ConstructorKind::Extends:
160              return true;
161          }
162          return false;
163      }
164      bool isClass() const
165      {
166          if (!m_rareData)
167              return false;
168          return !m_rareData->m_classSource.isNull();
169      }
170  
171      RefPtr<TDZEnvironmentLink> parentScopeTDZVariables() const
172      {
173          if (!m_rareData)
174              return nullptr;
175          return m_rareData->m_parentScopeTDZVariables;
176      }
177      
178      bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
179  
180      JSC::DerivedContextType derivedContextType() const {return static_cast<JSC::DerivedContextType>(m_derivedContextType); }
181  
182      String sourceURLDirective() const
183      {
184          if (m_rareData)
185              return m_rareData->m_sourceURLDirective;
186          return String();
187      }
188      String sourceMappingURLDirective() const
189      {
190          if (m_rareData)
191              return m_rareData->m_sourceMappingURLDirective;
192          return String();
193      }
194      void setSourceURLDirective(const String& sourceURL)
195      {
196          ensureRareData().m_sourceURLDirective = sourceURL;
197      }
198      void setSourceMappingURLDirective(const String& sourceMappingURL)
199      {
200          ensureRareData().m_sourceMappingURLDirective = sourceMappingURL;
201      }
202  
203      void finalizeUnconditionally(VM&);
204  
205      struct RareData {
206          WTF_MAKE_STRUCT_FAST_ALLOCATED;
207  
208          SourceCode m_classSource;
209          String m_sourceURLDirective;
210          String m_sourceMappingURLDirective;
211          RefPtr<TDZEnvironmentLink> m_parentScopeTDZVariables;
212          Vector<JSTextPosition> m_classFieldLocations;
213      };
214  
215      NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); }
216  
217      Vector<JSTextPosition>* classFieldLocations() const
218      {
219          if (m_rareData)
220              return &m_rareData->m_classFieldLocations;
221          return nullptr;
222      }
223  
224      void setClassFieldLocations(Vector<JSTextPosition>&& classFieldLocations)
225      {
226          if (classFieldLocations.isEmpty())
227              return;
228          ensureRareData().m_classFieldLocations = WTFMove(classFieldLocations);
229      }
230  
231  private:
232      UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, RefPtr<TDZEnvironmentLink>,  JSC::DerivedContextType, JSC::NeedsClassFieldInitializer, bool isBuiltinDefaultClassConstructor);
233      UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&);
234  
235      static void visitChildren(JSCell*, SlotVisitor&);
236  
237      void decodeCachedCodeBlocks(VM&);
238  
239      bool codeBlockEdgeMayBeWeak() const
240      {
241          // Currently, bytecode cache assumes that the tree of UnlinkedFunctionExecutable and UnlinkedCodeBlock will not be destroyed while the parent is live.
242          // Bytecode cache uses this asumption to avoid duplicate materialization by bookkeeping the heap cells in the offste-to-pointer map.
243          return VM::useUnlinkedCodeBlockJettisoning() && !m_isGeneratedFromCache;
244      }
245  
246      unsigned m_firstLineOffset : 31;
247      unsigned m_isInStrictContext : 1;
248      unsigned m_lineCount : 31;
249      unsigned m_hasCapturedVariables : 1;
250      unsigned m_unlinkedFunctionNameStart : 31;
251      unsigned m_isBuiltinFunction : 1;
252      unsigned m_unlinkedBodyStartColumn : 31;
253      unsigned m_isBuiltinDefaultClassConstructor : 1;
254      unsigned m_unlinkedBodyEndColumn : 31;
255      unsigned m_constructAbility: 1;
256      unsigned m_startOffset : 31;
257      unsigned m_scriptMode: 1; // JSParserScriptMode
258      unsigned m_sourceLength : 31;
259      unsigned m_superBinding : 1;
260      unsigned m_parametersStartOffset : 31;
261      unsigned m_isCached : 1;
262      unsigned m_typeProfilingStartOffset;
263      unsigned m_typeProfilingEndOffset;
264      unsigned m_parameterCount;
265      CodeFeatures m_features;
266      SourceParseMode m_sourceParseMode;
267      unsigned m_constructorKind : 2;
268      unsigned m_functionMode : 2; // FunctionMode
269      unsigned m_derivedContextType: 2;
270      unsigned m_isGeneratedFromCache : 1;
271      unsigned m_needsClassFieldInitializer : 1;
272  
273      union {
274          WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
275          RefPtr<Decoder> m_decoder;
276      };
277  
278      union {
279          WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
280          struct {
281              int32_t m_cachedCodeBlockForCallOffset;
282              int32_t m_cachedCodeBlockForConstructOffset;
283          };
284      };
285  
286      Identifier m_name;
287      Identifier m_ecmaName;
288  
289      RareData& ensureRareData()
290      {
291          if (LIKELY(m_rareData))
292              return *m_rareData;
293          return ensureRareDataSlow();
294      }
295      RareData& ensureRareDataSlow();
296  
297      std::unique_ptr<RareData> m_rareData;
298  
299  public:
300      static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
301      {
302          return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedFunctionExecutableType, StructureFlags), info());
303      }
304  
305      DECLARE_EXPORT_INFO;
306  };
307  
308  } // namespace JSC