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