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(JSGlobalObject*, CallFrame*);
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 static constexpr 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 static inline ptrdiff_t offsetOfGlobalObject()
128 {
129 return OBJECT_OFFSETOF(JSFunction, m_globalObject);
130 }
131
132 FunctionRareData* rareData(VM& vm)
133 {
134 if (UNLIKELY(!m_rareData))
135 return allocateRareData(vm);
136 return m_rareData.get();
137 }
138
139 FunctionRareData* ensureRareDataAndAllocationProfile(JSGlobalObject*, unsigned inlineCapacity);
140
141 FunctionRareData* rareData()
142 {
143 FunctionRareData* rareData = m_rareData.get();
144
145 // The JS thread may be concurrently creating the rare data
146 // If we see it, we want to ensure it has been properly created
147 WTF::loadLoadFence();
148
149 return rareData;
150 }
151
152 JSGlobalObject* globalObject() const { return m_globalObject.get(); }
153
154 bool isHostOrBuiltinFunction() const;
155 bool isBuiltinFunction() const;
156 JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
157 bool isClassConstructorFunction() const;
158
159 void setFunctionName(JSGlobalObject*, JSValue name);
160
161 // Returns the __proto__ for the |this| value if this JSFunction were to be constructed.
162 JSObject* prototypeForConstruction(VM&, JSGlobalObject*);
163
164 bool canUseAllocationProfile();
165 bool canUseAllocationProfileNonInline();
166
167 enum class PropertyStatus {
168 Eager,
169 Lazy,
170 Reified,
171 };
172 PropertyStatus reifyLazyPropertyIfNeeded(VM&, JSGlobalObject*, PropertyName);
173
174protected:
175 JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
176 JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
177
178 void finishCreation(VM&, NativeExecutable*, int length, const String& name);
179 void finishCreation(VM&);
180
181 static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
182 static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode = EnumerationMode());
183 static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
184
185 static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
186
187 static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
188
189 static void visitChildren(JSCell*, SlotVisitor&);
190
191private:
192 static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
193 {
194 JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope, structure);
195 ASSERT(function->structure(vm)->globalObject());
196 function->finishCreation(vm);
197 return function;
198 }
199
200 FunctionRareData* allocateRareData(VM&);
201 FunctionRareData* allocateAndInitializeRareData(JSGlobalObject*, size_t inlineCapacity);
202 FunctionRareData* initializeRareData(JSGlobalObject*, size_t inlineCapacity);
203
204 bool hasReifiedLength() const;
205 bool hasReifiedName() const;
206 void reifyLength(VM&);
207 void reifyName(VM&, JSGlobalObject*);
208 void reifyName(VM&, JSGlobalObject*, String name);
209
210 static bool isLazy(PropertyStatus property) { return property == PropertyStatus::Lazy || property == PropertyStatus::Reified; }
211 static bool isReified(PropertyStatus property) { return property == PropertyStatus::Reified; }
212
213 PropertyStatus reifyLazyPropertyForHostOrBuiltinIfNeeded(VM&, JSGlobalObject*, PropertyName);
214 PropertyStatus reifyLazyLengthIfNeeded(VM&, JSGlobalObject*, PropertyName);
215 PropertyStatus reifyLazyNameIfNeeded(VM&, JSGlobalObject*, PropertyName);
216 PropertyStatus reifyLazyBoundNameIfNeeded(VM&, JSGlobalObject*, PropertyName);
217
218#if ASSERT_DISABLED
219 void assertTypeInfoFlagInvariants() { }
220#else
221 void assertTypeInfoFlagInvariants();
222#endif
223
224 friend class LLIntOffsetsExtractor;
225
226 static EncodedJSValue argumentsGetter(JSGlobalObject*, EncodedJSValue, PropertyName);
227 static EncodedJSValue callerGetter(JSGlobalObject*, EncodedJSValue, PropertyName);
228
229 WriteBarrier<ExecutableBase> m_executable;
230 WriteBarrier<FunctionRareData> m_rareData;
231 WriteBarrier<JSGlobalObject> m_globalObject;
232};
233
234class JSStrictFunction final : public JSFunction {
235public:
236 using Base = JSFunction;
237
238 DECLARE_EXPORT_INFO;
239
240 static constexpr unsigned StructureFlags = Base::StructureFlags;
241
242 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
243 {
244 ASSERT(globalObject);
245 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
246 }
247};
248static_assert(sizeof(JSStrictFunction) == sizeof(JSFunction), "Allocated in JSFunction IsoSubspace");
249
250class JSSloppyFunction final : public JSFunction {
251public:
252 using Base = JSFunction;
253
254 DECLARE_EXPORT_INFO;
255
256 static constexpr unsigned StructureFlags = Base::StructureFlags;
257
258 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
259 {
260 ASSERT(globalObject);
261 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
262 }
263};
264static_assert(sizeof(JSSloppyFunction) == sizeof(JSFunction), "Allocated in JSFunction IsoSubspace");
265
266class JSArrowFunction final : public JSFunction {
267public:
268 using Base = JSFunction;
269
270 DECLARE_EXPORT_INFO;
271
272 static constexpr unsigned StructureFlags = Base::StructureFlags;
273
274 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
275 {
276 ASSERT(globalObject);
277 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
278 }
279};
280static_assert(sizeof(JSArrowFunction) == sizeof(JSFunction), "Allocated in JSFunction IsoSubspace");
281
282} // namespace JSC
283