1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Cameron Zwarich ([email protected])
5 * Copyright (C) 2007 Maks Orlovich
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#pragma once
25
26#include "FunctionRareData.h"
27#include "InternalFunction.h"
28#include "JSCallee.h"
29#include "JSScope.h"
30
31namespace JSC {
32
33class ExecutableBase;
34class FunctionExecutable;
35class FunctionPrototype;
36class JSLexicalEnvironment;
37class JSGlobalObject;
38class LLIntOffsetsExtractor;
39class NativeExecutable;
40class SourceCode;
41class InternalFunction;
42namespace DFG {
43class SpeculativeJIT;
44class JITCompiler;
45}
46
47namespace DOMJIT {
48class Signature;
49}
50
51
52JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
53
54JS_EXPORT_PRIVATE String getCalculatedDisplayName(VM&, JSObject*);
55
56class JSFunction : public JSCallee {
57 friend class JIT;
58 friend class DFG::SpeculativeJIT;
59 friend class DFG::JITCompiler;
60 friend class VM;
61 friend class InternalFunction;
62
63public:
64
65 template<typename CellType, SubspaceAccess>
66 static IsoSubspace* subspaceFor(VM& vm)
67 {
68 return &vm.functionSpace;
69 }
70
71 typedef JSCallee Base;
72 const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | OverridesGetCallData;
73
74 static size_t allocationSize(Checked<size_t> inlineCapacity)
75 {
76 ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
77 return sizeof(JSFunction);
78 }
79
80 static Structure* selectStructureForNewFuncExp(JSGlobalObject*, FunctionExecutable*);
81
82 JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor, const DOMJIT::Signature* = nullptr);
83 JS_EXPORT_PRIVATE static JSFunction* createFunctionThatMasqueradesAsUndefined(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor, const DOMJIT::Signature* = nullptr);
84
85 static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
86
87 JS_EXPORT_PRIVATE static JSFunction* create(VM&, FunctionExecutable*, JSScope*);
88 static JSFunction* create(VM&, FunctionExecutable*, JSScope*, Structure*);
89
90 JS_EXPORT_PRIVATE String name(VM&);
91 JS_EXPORT_PRIVATE String displayName(VM&);
92 JS_EXPORT_PRIVATE const String calculatedDisplayName(VM&);
93
94 ExecutableBase* executable() const { return m_executable.get(); }
95
96 // To call any of these methods include JSFunctionInlines.h
97 bool isHostFunction() const;
98 FunctionExecutable* jsExecutable() const;
99 Intrinsic intrinsic() const;
100
101 JS_EXPORT_PRIVATE const SourceCode* sourceCode() const;
102
103 DECLARE_EXPORT_INFO;
104
105 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
106 {
107 ASSERT(globalObject);
108 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
109 }
110
111 TaggedNativeFunction nativeFunction();
112 TaggedNativeFunction nativeConstructor();
113
114 static ConstructType getConstructData(JSCell*, ConstructData&);
115 static CallType getCallData(JSCell*, CallData&);
116
117 static inline ptrdiff_t offsetOfExecutable()
118 {
119 return OBJECT_OFFSETOF(JSFunction, m_executable);
120 }
121
122 static inline ptrdiff_t offsetOfRareData()
123 {
124 return OBJECT_OFFSETOF(JSFunction, m_rareData);
125 }
126
127 FunctionRareData* rareData(VM& vm)
128 {
129 if (UNLIKELY(!m_rareData))
130 return allocateRareData(vm);
131 return m_rareData.get();
132 }
133
134 FunctionRareData* ensureRareDataAndAllocationProfile(ExecState*, unsigned inlineCapacity);
135
136 FunctionRareData* rareData()
137 {
138 FunctionRareData* rareData = m_rareData.get();
139
140 // The JS thread may be concurrently creating the rare data
141 // If we see it, we want to ensure it has been properly created
142 WTF::loadLoadFence();
143
144 return rareData;
145 }
146
147 bool isHostOrBuiltinFunction() const;
148 bool isBuiltinFunction() const;
149 bool isAnonymousBuiltinFunction() const;
150 JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
151 bool isClassConstructorFunction() const;
152
153 void setFunctionName(ExecState*, JSValue name);
154
155 // Returns the __proto__ for the |this| value if this JSFunction were to be constructed.
156 JSObject* prototypeForConstruction(VM&, ExecState*);
157
158 bool canUseAllocationProfile();
159 bool canUseAllocationProfileNonInline();
160
161 enum class PropertyStatus {
162 Eager,
163 Lazy,
164 Reified,
165 };
166 PropertyStatus reifyLazyPropertyIfNeeded(VM&, ExecState*, PropertyName);
167
168protected:
169 JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
170 JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
171
172 void finishCreation(VM&, NativeExecutable*, int length, const String& name);
173 void finishCreation(VM&);
174
175 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
176 static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = EnumerationMode());
177 static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
178
179 static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
180
181 static bool deleteProperty(JSCell*, ExecState*, PropertyName);
182
183 static void visitChildren(JSCell*, SlotVisitor&);
184
185private:
186 static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
187 {
188 JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope, structure);
189 ASSERT(function->structure(vm)->globalObject());
190 function->finishCreation(vm);
191 return function;
192 }
193
194 FunctionRareData* allocateRareData(VM&);
195 FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity);
196 FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity);
197
198 bool hasReifiedLength() const;
199 bool hasReifiedName() const;
200 void reifyLength(VM&);
201 void reifyName(VM&, ExecState*);
202 void reifyName(VM&, ExecState*, String name);
203
204 static bool isLazy(PropertyStatus property) { return property == PropertyStatus::Lazy || property == PropertyStatus::Reified; }
205 static bool isReified(PropertyStatus property) { return property == PropertyStatus::Reified; }
206
207 PropertyStatus reifyLazyPropertyForHostOrBuiltinIfNeeded(VM&, ExecState*, PropertyName);
208 PropertyStatus reifyLazyLengthIfNeeded(VM&, ExecState*, PropertyName);
209 PropertyStatus reifyLazyNameIfNeeded(VM&, ExecState*, PropertyName);
210 PropertyStatus reifyLazyBoundNameIfNeeded(VM&, ExecState*, PropertyName);
211
212#if ASSERT_DISABLED
213 void assertTypeInfoFlagInvariants() { }
214#else
215 void assertTypeInfoFlagInvariants();
216#endif
217
218 friend class LLIntOffsetsExtractor;
219
220 static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, PropertyName);
221 static EncodedJSValue callerGetter(ExecState*, EncodedJSValue, PropertyName);
222 static EncodedJSValue lengthGetter(ExecState*, EncodedJSValue, PropertyName);
223 static EncodedJSValue nameGetter(ExecState*, EncodedJSValue, PropertyName);
224
225 WriteBarrier<ExecutableBase> m_executable;
226 WriteBarrier<FunctionRareData> m_rareData;
227};
228
229class JSStrictFunction final : public JSFunction {
230public:
231 using Base = JSFunction;
232
233 DECLARE_EXPORT_INFO;
234
235 static constexpr unsigned StructureFlags = Base::StructureFlags;
236
237 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
238 {
239 ASSERT(globalObject);
240 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
241 }
242};
243static_assert(sizeof(JSStrictFunction) == sizeof(JSFunction), "Allocated in JSFunction IsoSubspace");
244
245class JSSloppyFunction final : public JSFunction {
246public:
247 using Base = JSFunction;
248
249 DECLARE_EXPORT_INFO;
250
251 static constexpr unsigned StructureFlags = Base::StructureFlags;
252
253 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
254 {
255 ASSERT(globalObject);
256 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
257 }
258};
259static_assert(sizeof(JSSloppyFunction) == sizeof(JSFunction), "Allocated in JSFunction IsoSubspace");
260
261class JSArrowFunction final : public JSFunction {
262public:
263 using Base = JSFunction;
264
265 DECLARE_EXPORT_INFO;
266
267 static constexpr unsigned StructureFlags = Base::StructureFlags;
268
269 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
270 {
271 ASSERT(globalObject);
272 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
273 }
274};
275static_assert(sizeof(JSArrowFunction) == sizeof(JSFunction), "Allocated in JSFunction IsoSubspace");
276
277} // namespace JSC
278