1/*
2 * Copyright (C) 2009-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 "ExecutableToCodeBlockEdge.h"
29#include "ScriptExecutable.h"
30#include "SourceCode.h"
31#include <wtf/Box.h>
32#include <wtf/Markable.h>
33
34namespace JSC {
35
36struct FunctionOverrideInfo;
37
38class FunctionExecutable final : public ScriptExecutable {
39 friend class JIT;
40 friend class LLIntOffsetsExtractor;
41public:
42 typedef ScriptExecutable Base;
43 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
44
45 template<typename CellType, SubspaceAccess>
46 static IsoSubspace* subspaceFor(VM& vm)
47 {
48 return &vm.functionExecutableSpace.space;
49 }
50
51 static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, Intrinsic intrinsic)
52 {
53 FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, intrinsic);
54 executable->finishCreation(vm);
55 return executable;
56 }
57 static FunctionExecutable* fromGlobalCode(
58 const Identifier& name, ExecState&, const SourceCode&,
59 JSObject*& exception, int overrideLineNumber, Optional<int> functionConstructorParametersEndPosition);
60
61 static void destroy(JSCell*);
62
63 UnlinkedFunctionExecutable* unlinkedExecutable() const
64 {
65 return m_unlinkedExecutable.get();
66 }
67
68 // Returns either call or construct bytecode. This can be appropriate
69 // for answering questions that that don't vary between call and construct --
70 // for example, argumentsRegister().
71 FunctionCodeBlock* eitherCodeBlock()
72 {
73 ExecutableToCodeBlockEdge* edge;
74 if (m_codeBlockForCall)
75 edge = m_codeBlockForCall.get();
76 else
77 edge = m_codeBlockForConstruct.get();
78 return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(edge));
79 }
80
81 bool isGeneratedForCall() const
82 {
83 return !!m_codeBlockForCall;
84 }
85
86 FunctionCodeBlock* codeBlockForCall()
87 {
88 return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_codeBlockForCall.get()));
89 }
90
91 bool isGeneratedForConstruct() const
92 {
93 return !!m_codeBlockForConstruct;
94 }
95
96 FunctionCodeBlock* codeBlockForConstruct()
97 {
98 return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_codeBlockForConstruct.get()));
99 }
100
101 bool isGeneratedFor(CodeSpecializationKind kind)
102 {
103 if (kind == CodeForCall)
104 return isGeneratedForCall();
105 ASSERT(kind == CodeForConstruct);
106 return isGeneratedForConstruct();
107 }
108
109 FunctionCodeBlock* codeBlockFor(CodeSpecializationKind kind)
110 {
111 if (kind == CodeForCall)
112 return codeBlockForCall();
113 ASSERT(kind == CodeForConstruct);
114 return codeBlockForConstruct();
115 }
116
117 FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
118
119 FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
120 {
121 return baselineCodeBlockFor(kind);
122 }
123
124 RefPtr<TypeSet> returnStatementTypeSet()
125 {
126 RareData& rareData = ensureRareData();
127 if (!rareData.m_returnStatementTypeSet)
128 rareData.m_returnStatementTypeSet = TypeSet::create();
129 return rareData.m_returnStatementTypeSet;
130 }
131
132 FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
133 bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
134 ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
135 bool isClass() const { return m_unlinkedExecutable->isClass(); }
136 bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
137 bool isGetter() const { return parseMode() == SourceParseMode::GetterMode; }
138 bool isSetter() const { return parseMode() == SourceParseMode::SetterMode; }
139 bool isGenerator() const { return isGeneratorParseMode(parseMode()); }
140 bool isAsyncGenerator() const { return isAsyncGeneratorParseMode(parseMode()); }
141 bool isMethod() const { return parseMode() == SourceParseMode::MethodMode; }
142 bool hasCallerAndArgumentsProperties() const
143 {
144 // Per https://tc39.github.io/ecma262/#sec-forbidden-extensions, only sloppy-mode non-builtin functions in old-style (pre-ES6) syntactic forms can contain
145 // "caller" and "arguments".
146 return !isStrictMode() && parseMode() == SourceParseMode::NormalFunctionMode && !isClassConstructorFunction();
147 }
148 bool hasPrototypeProperty() const
149 {
150 return SourceParseModeSet(
151 SourceParseMode::NormalFunctionMode,
152 SourceParseMode::GeneratorBodyMode,
153 SourceParseMode::GeneratorWrapperFunctionMode,
154 SourceParseMode::GeneratorWrapperMethodMode,
155 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
156 SourceParseMode::AsyncGeneratorWrapperMethodMode,
157 SourceParseMode::AsyncGeneratorBodyMode
158 ).contains(parseMode()) || isClass();
159 }
160 DerivedContextType derivedContextType() const { return m_unlinkedExecutable->derivedContextType(); }
161 bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
162 const Identifier& name() { return m_unlinkedExecutable->name(); }
163 const Identifier& ecmaName() { return m_unlinkedExecutable->ecmaName(); }
164 const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
165 unsigned parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
166 SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
167 JSParserScriptMode scriptMode() const { return m_unlinkedExecutable->scriptMode(); }
168 SourceCode classSource() const { return m_unlinkedExecutable->classSource(); }
169
170 static void visitChildren(JSCell*, SlotVisitor&);
171 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
172 {
173 return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
174 }
175
176 void setOverrideLineNumber(int overrideLineNumber)
177 {
178 if (overrideLineNumber == -1) {
179 if (UNLIKELY(m_rareData))
180 m_rareData->m_overrideLineNumber = WTF::nullopt;
181 return;
182 }
183 ensureRareData().m_overrideLineNumber = overrideLineNumber;
184 }
185
186 Optional<int> overrideLineNumber() const
187 {
188 if (UNLIKELY(m_rareData))
189 return m_rareData->m_overrideLineNumber;
190 return WTF::nullopt;
191 }
192
193 int lineCount() const
194 {
195 if (UNLIKELY(m_rareData))
196 return m_rareData->m_lineCount;
197 return m_unlinkedExecutable->lineCount();
198 }
199
200 int endColumn() const
201 {
202 if (UNLIKELY(m_rareData))
203 return m_rareData->m_endColumn;
204 return m_unlinkedExecutable->linkedEndColumn(m_source.startColumn().oneBasedInt());
205 }
206
207 int firstLine() const
208 {
209 return source().firstLine().oneBasedInt();
210 }
211
212 int lastLine() const
213 {
214 return firstLine() + lineCount();
215 }
216
217 unsigned typeProfilingStartOffset(VM&) const
218 {
219 return typeProfilingStartOffset();
220 }
221
222 unsigned typeProfilingStartOffset() const
223 {
224 if (UNLIKELY(m_rareData))
225 return m_rareData->m_typeProfilingStartOffset;
226 return m_unlinkedExecutable->typeProfilingStartOffset();
227 }
228
229 unsigned typeProfilingEndOffset(VM&) const
230 {
231 return typeProfilingEndOffset();
232 }
233
234 unsigned typeProfilingEndOffset() const
235 {
236 if (UNLIKELY(m_rareData))
237 return m_rareData->m_typeProfilingEndOffset;
238 return m_unlinkedExecutable->typeProfilingEndOffset();
239 }
240
241 unsigned parametersStartOffset() const
242 {
243 if (UNLIKELY(m_rareData))
244 return m_rareData->m_parametersStartOffset;
245 return m_unlinkedExecutable->parametersStartOffset();
246 }
247
248 void overrideInfo(const FunctionOverrideInfo&);
249
250 DECLARE_INFO;
251
252 InferredValue* singletonFunction()
253 {
254 if (VM::canUseJIT())
255 return m_singletonFunction.get();
256 return nullptr;
257 }
258
259 void notifyCreation(VM& vm, JSValue value, const char* reason)
260 {
261 if (VM::canUseJIT()) {
262 singletonFunction()->notifyWrite(vm, value, reason);
263 return;
264 }
265 switch (m_singletonFunctionState) {
266 case ClearWatchpoint:
267 m_singletonFunctionState = IsWatched;
268 return;
269 case IsWatched:
270 m_singletonFunctionState = IsInvalidated;
271 return;
272 case IsInvalidated:
273 return;
274 }
275 }
276
277 bool singletonFunctionHasBeenInvalidated()
278 {
279 if (VM::canUseJIT())
280 return singletonFunction()->hasBeenInvalidated();
281 return m_singletonFunctionState == IsInvalidated;
282 }
283
284 // Cached poly proto structure for the result of constructing this executable.
285 Structure* cachedPolyProtoStructure() { return m_cachedPolyProtoStructure.get(); }
286 void setCachedPolyProtoStructure(VM& vm, Structure* structure) { m_cachedPolyProtoStructure.set(vm, this, structure); }
287
288 InlineWatchpointSet& ensurePolyProtoWatchpoint()
289 {
290 if (!m_polyProtoWatchpoint)
291 m_polyProtoWatchpoint = Box<InlineWatchpointSet>::create(IsWatched);
292 return *m_polyProtoWatchpoint;
293 }
294
295 Box<InlineWatchpointSet> sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
296
297private:
298 friend class ExecutableBase;
299 FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, Intrinsic);
300
301 void finishCreation(VM&);
302
303 friend class ScriptExecutable;
304
305 struct RareData {
306 WTF_MAKE_STRUCT_FAST_ALLOCATED;
307 RefPtr<TypeSet> m_returnStatementTypeSet;
308 unsigned m_lineCount;
309 unsigned m_endColumn;
310 Markable<int, IntegralMarkableTraits<int, -1>> m_overrideLineNumber;
311 unsigned m_parametersStartOffset { 0 };
312 unsigned m_typeProfilingStartOffset { UINT_MAX };
313 unsigned m_typeProfilingEndOffset { UINT_MAX };
314 };
315
316 RareData& ensureRareData()
317 {
318 if (LIKELY(m_rareData))
319 return *m_rareData;
320 return ensureRareDataSlow();
321 }
322 RareData& ensureRareDataSlow();
323
324 std::unique_ptr<RareData> m_rareData;
325 WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
326 WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
327 WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
328 union {
329 WriteBarrier<InferredValue> m_singletonFunction;
330 WatchpointState m_singletonFunctionState;
331 };
332 WriteBarrier<Structure> m_cachedPolyProtoStructure;
333 Box<InlineWatchpointSet> m_polyProtoWatchpoint;
334};
335
336} // namespace JSC
337