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