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 bool isAnonymousBuiltinFunction() const { return isBuiltinFunction() && name().isPrivateName(); }
149 ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
150 JSParserScriptMode scriptMode() const { return static_cast<JSParserScriptMode>(m_scriptMode); }
151 bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
152 bool isClass() const
153 {
154 if (!m_rareData)
155 return false;
156 return !m_rareData->m_classSource.isNull();
157 }
158
159 VariableEnvironment parentScopeTDZVariables() const
160 {
161 if (!m_rareData || !m_rareData->m_parentScopeTDZVariables)
162 return VariableEnvironment();
163 return m_rareData->m_parentScopeTDZVariables.environment().toVariableEnvironment();
164 }
165
166 bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
167
168 JSC::DerivedContextType derivedContextType() const {return static_cast<JSC::DerivedContextType>(m_derivedContextType); }
169
170 String sourceURLDirective() const
171 {
172 if (m_rareData)
173 return m_rareData->m_sourceURLDirective;
174 return String();
175 }
176 String sourceMappingURLDirective() const
177 {
178 if (m_rareData)
179 return m_rareData->m_sourceMappingURLDirective;
180 return String();
181 }
182 void setSourceURLDirective(const String& sourceURL)
183 {
184 ensureRareData().m_sourceURLDirective = sourceURL;
185 }
186 void setSourceMappingURLDirective(const String& sourceMappingURL)
187 {
188 ensureRareData().m_sourceMappingURLDirective = sourceMappingURL;
189 }
190
191 void finalizeUnconditionally(VM&);
192
193 struct RareData {
194 WTF_MAKE_STRUCT_FAST_ALLOCATED;
195
196 SourceCode m_classSource;
197 String m_sourceURLDirective;
198 String m_sourceMappingURLDirective;
199 CompactVariableMap::Handle m_parentScopeTDZVariables;
200 };
201
202private:
203 UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>, JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor);
204 UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&);
205
206 void decodeCachedCodeBlocks(VM&);
207
208 bool codeBlockEdgeMayBeWeak() const
209 {
210 // Currently, bytecode cache assumes that the tree of UnlinkedFunctionExecutable and UnlinkedCodeBlock will not be destroyed while the parent is live.
211 // Bytecode cache uses this asumption to avoid duplicate materialization by bookkeeping the heap cells in the offste-to-pointer map.
212 return VM::useUnlinkedCodeBlockJettisoning() && !m_isGeneratedFromCache;
213 }
214
215 unsigned m_firstLineOffset : 31;
216 unsigned m_isInStrictContext : 1;
217 unsigned m_lineCount : 31;
218 unsigned m_hasCapturedVariables : 1;
219 unsigned m_unlinkedFunctionNameStart : 31;
220 unsigned m_isBuiltinFunction : 1;
221 unsigned m_unlinkedBodyStartColumn : 31;
222 unsigned m_isBuiltinDefaultClassConstructor : 1;
223 unsigned m_unlinkedBodyEndColumn : 31;
224 unsigned m_constructAbility: 1;
225 unsigned m_startOffset : 31;
226 unsigned m_scriptMode: 1; // JSParserScriptMode
227 unsigned m_sourceLength : 31;
228 unsigned m_superBinding : 1;
229 unsigned m_parametersStartOffset : 31;
230 unsigned m_isCached : 1;
231 unsigned m_typeProfilingStartOffset;
232 unsigned m_typeProfilingEndOffset;
233 unsigned m_parameterCount;
234 CodeFeatures m_features;
235 SourceParseMode m_sourceParseMode;
236 unsigned m_constructorKind : 2;
237 unsigned m_functionMode : 2; // FunctionMode
238 unsigned m_derivedContextType: 2;
239 unsigned m_isGeneratedFromCache : 1;
240
241 union {
242 WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
243 RefPtr<Decoder> m_decoder;
244 };
245
246 union {
247 WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
248 struct {
249 int32_t m_cachedCodeBlockForCallOffset;
250 int32_t m_cachedCodeBlockForConstructOffset;
251 };
252 };
253
254 Identifier m_name;
255 Identifier m_ecmaName;
256
257 RareData& ensureRareData()
258 {
259 if (LIKELY(m_rareData))
260 return *m_rareData;
261 return ensureRareDataSlow();
262 }
263 RareData& ensureRareDataSlow();
264
265 std::unique_ptr<RareData> m_rareData;
266
267protected:
268 static void visitChildren(JSCell*, SlotVisitor&);
269
270public:
271 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
272 {
273 return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedFunctionExecutableType, StructureFlags), info());
274 }
275
276 DECLARE_EXPORT_INFO;
277};
278
279} // namespace JSC
280