1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
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
84 static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
85
86 JS_EXPORT_PRIVATE static JSFunction* create(VM&, FunctionExecutable*, JSScope*);
87 static JSFunction* create(VM&, FunctionExecutable*, JSScope*, Structure*);
88
89 JS_EXPORT_PRIVATE String name(VM&);
90 JS_EXPORT_PRIVATE String displayName(VM&);
91 JS_EXPORT_PRIVATE const String calculatedDisplayName(VM&);
92
93 ExecutableBase* executable() const { return m_executable.get(); }
94
95 // To call any of these methods include JSFunctionInlines.h
96 bool isHostFunction() const;
97 FunctionExecutable* jsExecutable() const;
98 Intrinsic intrinsic() const;
99
100 JS_EXPORT_PRIVATE const SourceCode* sourceCode() const;
101
102 DECLARE_EXPORT_INFO;
103
104 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
105 {
106 ASSERT(globalObject);
107 return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
108 }
109
110 TaggedNativeFunction nativeFunction();
111 TaggedNativeFunction nativeConstructor();
112
113 static ConstructType getConstructData(JSCell*, ConstructData&);
114 static CallType getCallData(JSCell*, CallData&);
115
116 static inline ptrdiff_t offsetOfExecutable()
117 {
118 return OBJECT_OFFSETOF(JSFunction, m_executable);
119 }
120
121 static inline ptrdiff_t offsetOfRareData()
122 {
123 return OBJECT_OFFSETOF(JSFunction, m_rareData);
124 }
125
126 FunctionRareData* rareData(VM& vm)
127 {
128 if (UNLIKELY(!m_rareData))
129 return allocateRareData(vm);
130 return m_rareData.get();
131 }
132
133 FunctionRareData* ensureRareDataAndAllocationProfile(ExecState*, unsigned inlineCapacity);
134
135 FunctionRareData* rareData()
136 {
137 FunctionRareData* rareData = m_rareData.get();
138
139 // The JS thread may be concurrently creating the rare data
140 // If we see it, we want to ensure it has been properly created
141 WTF::loadLoadFence();
142
143 return rareData;
144 }
145
146 bool isHostOrBuiltinFunction() const;
147 bool isBuiltinFunction() const;
148 JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
149 bool isClassConstructorFunction() const;
150
151 void setFunctionName(ExecState*, JSValue name);
152
153 // Returns the __proto__ for the |this| value if this JSFunction were to be constructed.
154 JSObject* prototypeForConstruction(VM&, ExecState*);
155
156 bool canUseAllocationProfile();
157 bool canUseAllocationProfileNonInline();
158
159 enum class PropertyStatus {
160 Eager,
161 Lazy,
162 Reified,
163 };
164 PropertyStatus reifyLazyPropertyIfNeeded(VM&, ExecState*, PropertyName);
165
166protected:
167 JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
168 JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
169
170 void finishCreation(VM&, NativeExecutable*, int length, const String& name);
171 void finishCreation(VM&);
172
173 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
174 static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = EnumerationMode());
175 static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
176
177 static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
178
179 static bool deleteProperty(JSCell*, ExecState*, PropertyName);
180
181 static void visitChildren(JSCell*, SlotVisitor&);
182
183private:
184 static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
185 {
186 JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope, structure);
187 ASSERT(function->structure(vm)->globalObject());
188 function->finishCreation(vm);
189 return function;
190 }
191
192 FunctionRareData* allocateRareData(VM&);
193 FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity);
194 FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity);
195
196 bool hasReifiedLength() const;
197 bool hasReifiedName() const;
198 void reifyLength(VM&);
199 void reifyName(VM&, ExecState*);
200 void reifyName(VM&, ExecState*, String name);
201
202 static bool isLazy(PropertyStatus property) { return property == PropertyStatus::Lazy || property == PropertyStatus::Reified; }
203 static bool isReified(PropertyStatus property) { return property == PropertyStatus::Reified; }
204
205 PropertyStatus reifyLazyPropertyForHostOrBuiltinIfNeeded(VM&, ExecState*, PropertyName);
206 PropertyStatus reifyLazyLengthIfNeeded(VM&, ExecState*, PropertyName);
207 PropertyStatus reifyLazyNameIfNeeded(VM&, ExecState*, PropertyName);
208 PropertyStatus reifyLazyBoundNameIfNeeded(VM&, ExecState*, PropertyName);
209
210#if ASSERT_DISABLED
211 void assertTypeInfoFlagInvariants() { }
212#else
213 void assertTypeInfoFlagInvariants();
214#endif
215
216 friend class LLIntOffsetsExtractor;
217
218 static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, PropertyName);
219 static EncodedJSValue callerGetter(ExecState*, EncodedJSValue, PropertyName);
220 static EncodedJSValue lengthGetter(ExecState*, EncodedJSValue, PropertyName);
221 static EncodedJSValue nameGetter(ExecState*, EncodedJSValue, PropertyName);
222
223 WriteBarrier<ExecutableBase> m_executable;
224 WriteBarrier<FunctionRareData> m_rareData;
225};
226
227} // namespace JSC
228