ScriptExecutable.h
1 /* 2 * Copyright (C) 2009-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 "ExecutableBase.h" 29 30 namespace JSC { 31 32 class JSArray; 33 class JSTemplateObjectDescriptor; 34 class IsoCellSet; 35 36 class ScriptExecutable : public ExecutableBase { 37 public: 38 typedef ExecutableBase Base; 39 static constexpr unsigned StructureFlags = Base::StructureFlags; 40 41 static void destroy(JSCell*); 42 43 using TemplateObjectMap = HashMap<uint64_t, WriteBarrier<JSArray>, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>>; 44 45 CodeBlockHash hashFor(CodeSpecializationKind) const; 46 47 const SourceCode& source() const { return m_source; } 48 intptr_t sourceID() const { return m_source.providerID(); } 49 const SourceOrigin& sourceOrigin() const { return m_source.provider()->sourceOrigin(); } 50 // This is NOT the path that should be used for computing relative paths from a script. Use SourceOrigin's URL for that, the values may or may not be the same... This should only be used for `error.sourceURL` and stack traces. 51 const String& sourceURL() const { return m_source.provider()->sourceURL(); } 52 int firstLine() const { return m_source.firstLine().oneBasedInt(); } 53 JS_EXPORT_PRIVATE int lastLine() const; 54 unsigned startColumn() const { return m_source.startColumn().oneBasedInt(); } 55 JS_EXPORT_PRIVATE unsigned endColumn() const; 56 57 Optional<int> overrideLineNumber(VM&) const; 58 unsigned typeProfilingStartOffset(VM&) const; 59 unsigned typeProfilingEndOffset(VM&) const; 60 61 bool usesEval() const { return m_features & EvalFeature; } 62 bool usesArguments() const { return m_features & ArgumentsFeature; } 63 bool isArrowFunctionContext() const { return m_isArrowFunctionContext; } 64 DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); } 65 EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); } 66 bool isInStrictContext() const { return m_features & StrictModeFeature; } 67 bool usesNonSimpleParameterList() const { return m_features & NonSimpleParameterListFeature; } 68 69 void setNeverInline(bool value) { m_neverInline = value; } 70 void setNeverOptimize(bool value) { m_neverOptimize = value; } 71 void setNeverFTLOptimize(bool value) { m_neverFTLOptimize = value; } 72 void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; } 73 void setCanUseOSRExitFuzzing(bool value) { m_canUseOSRExitFuzzing = value; } 74 bool neverInline() const { return m_neverInline; } 75 bool neverOptimize() const { return m_neverOptimize; } 76 bool neverFTLOptimize() const { return m_neverFTLOptimize; } 77 bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; } 78 bool isInliningCandidate() const { return !neverInline(); } 79 bool isOkToOptimize() const { return !neverOptimize(); } 80 bool canUseOSRExitFuzzing() const { return m_canUseOSRExitFuzzing; } 81 bool isInsideOrdinaryFunction() const { return m_isInsideOrdinaryFunction; } 82 83 bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; } 84 85 CodeFeatures features() const { return m_features; } 86 87 DECLARE_EXPORT_INFO; 88 89 void recordParse(CodeFeatures, bool hasCapturedVariables, int lastLine, unsigned endColumn); 90 void installCode(CodeBlock*); 91 void installCode(VM&, CodeBlock*, CodeType, CodeSpecializationKind); 92 CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, Exception*&); 93 CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind); 94 95 void clearCode(IsoCellSet&); 96 97 Intrinsic intrinsic() const 98 { 99 return m_intrinsic; 100 } 101 102 bool hasJITCodeForCall() const 103 { 104 return m_jitCodeForCall; 105 } 106 bool hasJITCodeForConstruct() const 107 { 108 return m_jitCodeForConstruct; 109 } 110 111 // This function has an interesting GC story. Callers of this function are asking us to create a CodeBlock 112 // that is not jettisoned before this function returns. Callers are essentially asking for a strong reference 113 // to the CodeBlock. Because the Executable may be allocating the CodeBlock, we require callers to pass in 114 // their CodeBlock*& reference because it's safe for CodeBlock to be jettisoned if Executable is the only thing 115 // to point to it. This forces callers to have a CodeBlock* in a register or on the stack that will be marked 116 // by conservative GC if a GC happens after we create the CodeBlock. 117 template <typename ExecutableType> 118 Exception* prepareForExecution(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock); 119 120 ScriptExecutable* topLevelExecutable(); 121 JSArray* createTemplateObject(JSGlobalObject*, JSTemplateObjectDescriptor*); 122 123 private: 124 friend class ExecutableBase; 125 Exception* prepareForExecutionImpl(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&); 126 127 bool hasClearableCode(VM&) const; 128 129 TemplateObjectMap& ensureTemplateObjectMap(VM&); 130 131 protected: 132 ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType, Intrinsic); 133 134 void finishCreation(VM& vm) 135 { 136 Base::finishCreation(vm); 137 138 #if ENABLE(CODEBLOCK_SAMPLING) 139 if (SamplingTool* sampler = vm.interpreter->sampler()) 140 sampler->notifyOfScope(vm, this); 141 #endif 142 } 143 144 void recordParse(CodeFeatures features, bool hasCapturedVariables) 145 { 146 m_features = features; 147 m_hasCapturedVariables = hasCapturedVariables; 148 } 149 150 static TemplateObjectMap& ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest); 151 152 SourceCode m_source; 153 Intrinsic m_intrinsic { NoIntrinsic }; 154 bool m_didTryToEnterInLoop { false }; 155 CodeFeatures m_features; 156 OptionSet<CodeGenerationMode> m_codeGenerationModeForGeneratorBody; 157 bool m_hasCapturedVariables : 1; 158 bool m_neverInline : 1; 159 bool m_neverOptimize : 1; 160 bool m_neverFTLOptimize : 1; 161 bool m_isArrowFunctionContext : 1; 162 bool m_canUseOSRExitFuzzing : 1; 163 bool m_codeForGeneratorBodyWasGenerated : 1; 164 bool m_isInsideOrdinaryFunction : 1; 165 unsigned m_derivedContextType : 2; // DerivedContextType 166 unsigned m_evalContextType : 2; // EvalContextType 167 }; 168 169 } // namespace JSC