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
30namespace JSC {
31
32class JSArray;
33class JSTemplateObjectDescriptor;
34class IsoCellSet;
35
36class ScriptExecutable : public ExecutableBase {
37public:
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 const String& sourceURL() const { return m_source.provider()->url(); }
51 int firstLine() const { return m_source.firstLine().oneBasedInt(); }
52 JS_EXPORT_PRIVATE int lastLine() const;
53 unsigned startColumn() const { return m_source.startColumn().oneBasedInt(); }
54 JS_EXPORT_PRIVATE unsigned endColumn() const;
55
56 Optional<int> overrideLineNumber(VM&) const;
57 unsigned typeProfilingStartOffset(VM&) const;
58 unsigned typeProfilingEndOffset(VM&) const;
59
60 bool usesEval() const { return m_features & EvalFeature; }
61 bool usesArguments() const { return m_features & ArgumentsFeature; }
62 bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
63 bool isStrictMode() const { return m_features & StrictModeFeature; }
64 DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
65 EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); }
66
67 ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
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
82 bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; }
83
84 CodeFeatures features() const { return m_features; }
85
86 DECLARE_EXPORT_INFO;
87
88 void recordParse(CodeFeatures, bool hasCapturedVariables, int lastLine, unsigned endColumn);
89 void installCode(CodeBlock*);
90 void installCode(VM&, CodeBlock*, CodeType, CodeSpecializationKind);
91 CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, Exception*&);
92 CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind);
93
94 void clearCode(IsoCellSet&);
95
96 Intrinsic intrinsic() const
97 {
98 return m_intrinsic;
99 }
100
101 bool hasJITCodeForCall() const
102 {
103 return m_jitCodeForCall;
104 }
105 bool hasJITCodeForConstruct() const
106 {
107 return m_jitCodeForConstruct;
108 }
109
110 // This function has an interesting GC story. Callers of this function are asking us to create a CodeBlock
111 // that is not jettisoned before this function returns. Callers are essentially asking for a strong reference
112 // to the CodeBlock. Because the Executable may be allocating the CodeBlock, we require callers to pass in
113 // their CodeBlock*& reference because it's safe for CodeBlock to be jettisoned if Executable is the only thing
114 // to point to it. This forces callers to have a CodeBlock* in a register or on the stack that will be marked
115 // by conservative GC if a GC happens after we create the CodeBlock.
116 template <typename ExecutableType>
117 Exception* prepareForExecution(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock);
118
119 ScriptExecutable* topLevelExecutable();
120 JSArray* createTemplateObject(JSGlobalObject*, JSTemplateObjectDescriptor*);
121
122private:
123 friend class ExecutableBase;
124 Exception* prepareForExecutionImpl(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&);
125
126 bool hasClearableCode(VM&) const;
127
128 TemplateObjectMap& ensureTemplateObjectMap(VM&);
129
130protected:
131 ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext, EvalContextType, Intrinsic);
132
133 void finishCreation(VM& vm)
134 {
135 Base::finishCreation(vm);
136
137#if ENABLE(CODEBLOCK_SAMPLING)
138 if (SamplingTool* sampler = vm.interpreter->sampler())
139 sampler->notifyOfScope(vm, this);
140#endif
141 }
142
143 void recordParse(CodeFeatures features, bool hasCapturedVariables)
144 {
145 m_features = features;
146 m_hasCapturedVariables = hasCapturedVariables;
147 }
148
149 static TemplateObjectMap& ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest);
150
151 SourceCode m_source;
152 Intrinsic m_intrinsic { NoIntrinsic };
153 bool m_didTryToEnterInLoop { false };
154 CodeFeatures m_features;
155 OptionSet<CodeGenerationMode> m_codeGenerationModeForGeneratorBody;
156 bool m_hasCapturedVariables : 1;
157 bool m_neverInline : 1;
158 bool m_neverOptimize : 1;
159 bool m_neverFTLOptimize : 1;
160 bool m_isArrowFunctionContext : 1;
161 bool m_canUseOSRExitFuzzing : 1;
162 bool m_codeForGeneratorBodyWasGenerated : 1;
163 unsigned m_derivedContextType : 2; // DerivedContextType
164 unsigned m_evalContextType : 2; // EvalContextType
165};
166
167} // namespace JSC
168