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