/src/mozilla-central/js/src/vm/JSFunction.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef vm_JSFunction_h |
8 | | #define vm_JSFunction_h |
9 | | |
10 | | /* |
11 | | * JS function definitions. |
12 | | */ |
13 | | |
14 | | #include "jstypes.h" |
15 | | |
16 | | #include "vm/JSObject.h" |
17 | | #include "vm/JSScript.h" |
18 | | |
19 | | namespace js { |
20 | | |
21 | | class FunctionExtended; |
22 | | |
23 | | typedef JSNative Native; |
24 | | } // namespace js |
25 | | |
26 | | struct JSAtomState; |
27 | | |
28 | | static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2; |
29 | | static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3; |
30 | | static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4; |
31 | | |
32 | | static const char FunctionConstructorMedialSigils[] = ") {\n"; |
33 | | static const char FunctionConstructorFinalBrace[] = "\n}"; |
34 | | |
35 | | enum class FunctionPrefixKind { |
36 | | None, |
37 | | Get, |
38 | | Set |
39 | | }; |
40 | | |
41 | | class JSFunction : public js::NativeObject |
42 | | { |
43 | | public: |
44 | | static const js::Class class_; |
45 | | |
46 | | enum FunctionKind { |
47 | | NormalFunction = 0, |
48 | | Arrow, /* ES6 '(args) => body' syntax */ |
49 | | Method, /* ES6 MethodDefinition */ |
50 | | ClassConstructor, |
51 | | Getter, |
52 | | Setter, |
53 | | AsmJS, /* function is an asm.js module or exported function */ |
54 | | FunctionKindLimit |
55 | | }; |
56 | | |
57 | | enum Flags { |
58 | | INTERPRETED = 0x0001, /* function has a JSScript and environment. */ |
59 | | CONSTRUCTOR = 0x0002, /* function that can be called as a constructor */ |
60 | | EXTENDED = 0x0004, /* structure is FunctionExtended */ |
61 | | BOUND_FUN = 0x0008, /* function was created with Function.prototype.bind. */ |
62 | | WASM_OPTIMIZED = 0x0010, /* asm.js/wasm function that has a jit entry */ |
63 | | HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a |
64 | | name was guessed for it anyway. See |
65 | | atom_ for more info about this flag. */ |
66 | | HAS_BOUND_FUNCTION_NAME_PREFIX = 0x0020, /* bound functions reuse the HAS_GUESSED_ATOM |
67 | | flag to track if atom_ already contains the |
68 | | "bound " function name prefix */ |
69 | | LAMBDA = 0x0040, /* function comes from a FunctionExpression, ArrowFunction, or |
70 | | Function() call (not a FunctionDeclaration or nonstandard |
71 | | function-statement) */ |
72 | | SELF_HOSTED = 0x0080, /* function is self-hosted builtin and must not be |
73 | | decompilable nor constructible. */ |
74 | | HAS_INFERRED_NAME = 0x0100, /* function had no explicit name, but a name was |
75 | | set by SetFunctionName at compile time or |
76 | | SetFunctionNameIfNoOwnName at runtime. See |
77 | | atom_ for more info about this flag. */ |
78 | | INTERPRETED_LAZY = 0x0200, /* function is interpreted but doesn't have a script yet */ |
79 | | RESOLVED_LENGTH = 0x0400, /* f.length has been resolved (see fun_resolve). */ |
80 | | RESOLVED_NAME = 0x0800, /* f.name has been resolved (see fun_resolve). */ |
81 | | NEW_SCRIPT_CLEARED = 0x1000, /* For a function used as an interpreted constructor, whether |
82 | | a 'new' type had constructor information cleared. */ |
83 | | |
84 | | FUNCTION_KIND_SHIFT = 13, |
85 | | FUNCTION_KIND_MASK = 0x7 << FUNCTION_KIND_SHIFT, |
86 | | |
87 | | ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT, |
88 | | ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT, |
89 | | METHOD_KIND = Method << FUNCTION_KIND_SHIFT, |
90 | | CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT, |
91 | | GETTER_KIND = Getter << FUNCTION_KIND_SHIFT, |
92 | | SETTER_KIND = Setter << FUNCTION_KIND_SHIFT, |
93 | | |
94 | | /* Derived Flags values for convenience: */ |
95 | | NATIVE_FUN = 0, |
96 | | NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR, |
97 | | NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND, |
98 | | ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR, |
99 | | ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA, |
100 | | ASMJS_NATIVE = ASMJS_KIND | NATIVE_FUN, |
101 | | WASM_FUN = NATIVE_FUN | WASM_OPTIMIZED, |
102 | | INTERPRETED_METHOD = INTERPRETED | METHOD_KIND, |
103 | | INTERPRETED_METHOD_GENERATOR_OR_ASYNC = INTERPRETED | METHOD_KIND, |
104 | | INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR, |
105 | | INTERPRETED_GETTER = INTERPRETED | GETTER_KIND, |
106 | | INTERPRETED_SETTER = INTERPRETED | SETTER_KIND, |
107 | | INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR, |
108 | | INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND, |
109 | | INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = INTERPRETED | LAMBDA, |
110 | | INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR, |
111 | | INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED, |
112 | | NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME, |
113 | | |
114 | | STABLE_ACROSS_CLONES = CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK |
115 | | }; |
116 | | |
117 | | static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS, |
118 | | "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong"); |
119 | | static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK, |
120 | | "FunctionKind doesn't fit into flags_"); |
121 | | |
122 | | private: |
123 | | uint16_t nargs_; /* number of formal arguments |
124 | | (including defaults and the rest parameter unlike f.length) */ |
125 | | uint16_t flags_; /* bitfield composed of the above Flags enum, as well as the kind */ |
126 | | union U { |
127 | | class { |
128 | | friend class JSFunction; |
129 | | js::Native func_; /* native method pointer or null */ |
130 | | union { |
131 | | // Information about this function to be used by the JIT, only |
132 | | // used if isBuiltinNative(); use the accessor! |
133 | | const JSJitInfo* jitInfo_; |
134 | | // asm.js function index, only used if isAsmJSNative(). |
135 | | size_t asmJSFuncIndex_; |
136 | | // for wasm, a pointer to a fast jit->wasm table entry. |
137 | | void** wasmJitEntry_; |
138 | | } extra; |
139 | | } native; |
140 | | struct { |
141 | | JSObject* env_; /* environment for new activations */ |
142 | | union { |
143 | | JSScript* script_; /* interpreted bytecode descriptor or |
144 | | null; use the accessor! */ |
145 | | js::LazyScript* lazy_; /* lazily compiled script, or nullptr */ |
146 | | } s; |
147 | | } scripted; |
148 | | } u; |
149 | | |
150 | | // The |atom_| field can have different meanings depending on the function |
151 | | // type and flags. It is used for diagnostics, decompiling, and |
152 | | // |
153 | | // 1. If the function is not a bound function: |
154 | | // a. If HAS_GUESSED_ATOM is not set, to store the initial value of the |
155 | | // "name" property of functions. But also see RESOLVED_NAME. |
156 | | // b. If HAS_GUESSED_ATOM is set, |atom_| is only used for diagnostics, |
157 | | // but must not be used for the "name" property. |
158 | | // c. If HAS_INFERRED_NAME is set, the function wasn't given an explicit |
159 | | // name in the source text, e.g. |function fn(){}|, but instead it |
160 | | // was inferred based on how the function was defined in the source |
161 | | // text. The exact name inference rules are defined in the ECMAScript |
162 | | // specification. |
163 | | // Name inference can happen at compile-time, for example in |
164 | | // |var fn = function(){}|, or it can happen at runtime, for example |
165 | | // in |var o = {[Symbol.iterator]: function(){}}|. When it happens at |
166 | | // compile-time, the HAS_INFERRED_NAME is set directly in the |
167 | | // bytecode emitter, when it happens at runtime, the flag is set when |
168 | | // evaluating the JSOP_SETFUNNAME bytecode. |
169 | | // d. HAS_GUESSED_ATOM and HAS_INFERRED_NAME cannot both be set. |
170 | | // e. |atom_| can be null if neither an explicit, nor inferred, nor a |
171 | | // guessed name was set. |
172 | | // f. HAS_INFERRED_NAME can be set for cloned singleton function, even |
173 | | // though the clone shouldn't receive an inferred name. See the |
174 | | // comments in NewFunctionClone() and SetFunctionNameIfNoOwnName() |
175 | | // for details. |
176 | | // |
177 | | // 2. If the function is a bound function: |
178 | | // a. To store the initial value of the "name" property. |
179 | | // b. If HAS_BOUND_FUNCTION_NAME_PREFIX is not set, |atom_| doesn't |
180 | | // contain the "bound " prefix which is prepended to the "name" |
181 | | // property of bound functions per ECMAScript. |
182 | | // c. Bound functions can never have an inferred or guessed name. |
183 | | // d. |atom_| is never null for bound functions. |
184 | | js::GCPtrAtom atom_; |
185 | | |
186 | | public: |
187 | | static inline JS::Result<JSFunction*, JS::OOM&> |
188 | | create(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap, |
189 | | js::HandleShape shape, js::HandleObjectGroup group); |
190 | | |
191 | | /* Call objects must be created for each invocation of this function. */ |
192 | 323 | bool needsCallObject() const { |
193 | 323 | MOZ_ASSERT(!isInterpretedLazy()); |
194 | 323 | |
195 | 323 | if (isNative()) { |
196 | 0 | return false; |
197 | 0 | } |
198 | 323 | |
199 | 323 | // Note: this should be kept in sync with |
200 | 323 | // FunctionBox::needsCallObjectRegardlessOfBindings(). |
201 | 323 | MOZ_ASSERT_IF(nonLazyScript()->funHasExtensibleScope() || |
202 | 323 | nonLazyScript()->needsHomeObject() || |
203 | 323 | nonLazyScript()->isDerivedClassConstructor() || |
204 | 323 | isGenerator() || |
205 | 323 | isAsync(), |
206 | 323 | nonLazyScript()->bodyScope()->hasEnvironment()); |
207 | 323 | |
208 | 323 | return nonLazyScript()->bodyScope()->hasEnvironment(); |
209 | 323 | } |
210 | | |
211 | | bool needsExtraBodyVarEnvironment() const; |
212 | | bool needsNamedLambdaEnvironment() const; |
213 | | |
214 | 217 | bool needsFunctionEnvironmentObjects() const { |
215 | 217 | return needsCallObject() || needsNamedLambdaEnvironment(); |
216 | 217 | } |
217 | | |
218 | 40 | bool needsSomeEnvironmentObject() const { |
219 | 40 | return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment(); |
220 | 40 | } |
221 | | |
222 | 1.62M | size_t nargs() const { |
223 | 1.62M | return nargs_; |
224 | 1.62M | } |
225 | | |
226 | 32.5M | uint16_t flags() const { |
227 | 32.5M | return flags_; |
228 | 32.5M | } |
229 | | |
230 | 11.3M | FunctionKind kind() const { |
231 | 11.3M | return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> FUNCTION_KIND_SHIFT); |
232 | 11.3M | } |
233 | | |
234 | | /* A function can be classified as either native (C++) or interpreted (JS): */ |
235 | 21.1M | bool isInterpreted() const { return flags() & (INTERPRETED | INTERPRETED_LAZY); } |
236 | 17.8M | bool isNative() const { return !isInterpreted(); } |
237 | | |
238 | 26 | bool isConstructor() const { return flags() & CONSTRUCTOR; } |
239 | | |
240 | | /* Possible attributes of a native function: */ |
241 | 4.87M | bool isAsmJSNative() const { return kind() == AsmJS; } |
242 | 8.12M | bool isWasmOptimized() const { return (flags() & WASM_OPTIMIZED); } |
243 | 4.87M | bool isBuiltinNative() const { return isNativeWithCppEntry() && !isAsmJSNative(); } |
244 | | |
245 | | // May be called from the JIT with the wasmJitEntry_ field. |
246 | 195 | bool isNativeWithJitEntry() const { return isNative() && isWasmOptimized(); } |
247 | | // Must be called from the JIT with the native_ field. |
248 | 4.87M | bool isNativeWithCppEntry() const { return isNative() && !isWasmOptimized(); } |
249 | | |
250 | | /* Possible attributes of an interpreted function: */ |
251 | 10 | bool isBoundFunction() const { return flags() & BOUND_FUN; } |
252 | 4.99k | bool hasInferredName() const { return flags() & HAS_INFERRED_NAME; } |
253 | 5.02k | bool hasGuessedAtom() const { |
254 | 5.02k | static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX, |
255 | 5.02k | "HAS_GUESSED_ATOM is unused for bound functions"); |
256 | 5.02k | return (flags() & (HAS_GUESSED_ATOM | BOUND_FUN)) == HAS_GUESSED_ATOM; |
257 | 5.02k | } |
258 | 0 | bool hasBoundFunctionNamePrefix() const { |
259 | 0 | static_assert(HAS_BOUND_FUNCTION_NAME_PREFIX == HAS_GUESSED_ATOM, |
260 | 0 | "HAS_BOUND_FUNCTION_NAME_PREFIX is only used for bound functions"); |
261 | 0 | MOZ_ASSERT(isBoundFunction()); |
262 | 0 | return flags() & HAS_BOUND_FUNCTION_NAME_PREFIX; |
263 | 0 | } |
264 | 6.22k | bool isLambda() const { return flags() & LAMBDA; } |
265 | 3.25M | bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; } |
266 | | |
267 | | // This method doesn't check the non-nullness of u.scripted.s.script_, |
268 | | // because it's guaranteed to be non-null when this has INTERPRETED flag, |
269 | | // for live JSFunctions. |
270 | | // |
271 | | // When this JSFunction instance is reached via GC iteration, the above |
272 | | // doesn't hold, and hasUncompletedScript should also be checked. |
273 | | // (see the comment above hasUncompletedScript for more details). |
274 | 6.34k | bool hasScript() const { return flags() & INTERPRETED; } |
275 | | |
276 | | bool infallibleIsDefaultClassConstructor(JSContext* cx) const; |
277 | | |
278 | | // Arrow functions store their lexical new.target in the first extended slot. |
279 | 1.78k | bool isArrow() const { return kind() == Arrow; } |
280 | | // Every class-constructor is also a method. |
281 | 1.46k | bool isMethod() const { return kind() == Method || kind() == ClassConstructor; } |
282 | 6.48M | bool isClassConstructor() const { return kind() == ClassConstructor; } |
283 | | |
284 | 1.44k | bool isGetter() const { return kind() == Getter; } |
285 | 1.43k | bool isSetter() const { return kind() == Setter; } |
286 | | |
287 | 1.46k | bool allowSuperProperty() const { |
288 | 1.46k | return isMethod() || isGetter() || isSetter(); |
289 | 1.46k | } |
290 | | |
291 | 0 | bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; } |
292 | 0 | bool hasResolvedName() const { return flags() & RESOLVED_NAME; } |
293 | | |
294 | 30 | bool isSelfHostedOrIntrinsic() const { return flags() & SELF_HOSTED; } |
295 | 30 | bool isSelfHostedBuiltin() const { return isSelfHostedOrIntrinsic() && !isNative(); } |
296 | 0 | bool isIntrinsic() const { return isSelfHostedOrIntrinsic() && isNative(); } |
297 | | |
298 | 0 | bool hasJITCode() const { |
299 | 0 | if (!hasScript()) { |
300 | 0 | return false; |
301 | 0 | } |
302 | 0 | |
303 | 0 | return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript(); |
304 | 0 | } |
305 | 10 | bool hasJitEntry() const { |
306 | 10 | return hasScript() || isNativeWithJitEntry(); |
307 | 10 | } |
308 | | |
309 | | /* Compound attributes: */ |
310 | 36 | bool isBuiltin() const { |
311 | 36 | return isBuiltinNative() || isNativeWithJitEntry() || isSelfHostedBuiltin(); |
312 | 36 | } |
313 | | |
314 | 6.22k | bool isNamedLambda() const { |
315 | 6.22k | return isLambda() && displayAtom() && !hasInferredName() && !hasGuessedAtom(); |
316 | 6.22k | } |
317 | | |
318 | 0 | bool hasLexicalThis() const { |
319 | 0 | return isArrow(); |
320 | 0 | } |
321 | | |
322 | | bool isBuiltinFunctionConstructor(); |
323 | | bool needsPrototypeProperty(); |
324 | | |
325 | | /* Returns the strictness of this function, which must be interpreted. */ |
326 | 0 | bool strict() const { |
327 | 0 | MOZ_ASSERT(isInterpreted()); |
328 | 0 | return isInterpretedLazy() ? lazyScript()->strict() : nonLazyScript()->strict(); |
329 | 0 | } |
330 | | |
331 | 6.50M | void setFlags(uint16_t flags) { |
332 | 6.50M | this->flags_ = flags; |
333 | 6.50M | } |
334 | 0 | void setKind(FunctionKind kind) { |
335 | 0 | this->flags_ &= ~FUNCTION_KIND_MASK; |
336 | 0 | this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT; |
337 | 0 | } |
338 | | |
339 | | // Make the function constructible. |
340 | 6 | void setIsConstructor() { |
341 | 6 | MOZ_ASSERT(!isConstructor()); |
342 | 6 | MOZ_ASSERT(isSelfHostedBuiltin()); |
343 | 6 | flags_ |= CONSTRUCTOR; |
344 | 6 | } |
345 | | |
346 | 0 | void setIsClassConstructor() { |
347 | 0 | MOZ_ASSERT(!isClassConstructor()); |
348 | 0 | MOZ_ASSERT(isConstructor()); |
349 | 0 |
|
350 | 0 | setKind(ClassConstructor); |
351 | 0 | } |
352 | | |
353 | | // Can be called multiple times by the parser. |
354 | 3.25M | void setArgCount(uint16_t nargs) { |
355 | 3.25M | this->nargs_ = nargs; |
356 | 3.25M | } |
357 | | |
358 | 0 | void setIsBoundFunction() { |
359 | 0 | MOZ_ASSERT(!isBoundFunction()); |
360 | 0 | flags_ |= BOUND_FUN; |
361 | 0 | } |
362 | | |
363 | 1.54k | void setIsSelfHostedBuiltin() { |
364 | 1.54k | MOZ_ASSERT(isInterpreted()); |
365 | 1.54k | MOZ_ASSERT(!isSelfHostedBuiltin()); |
366 | 1.54k | flags_ |= SELF_HOSTED; |
367 | 1.54k | // Self-hosted functions should not be constructable. |
368 | 1.54k | flags_ &= ~CONSTRUCTOR; |
369 | 1.54k | } |
370 | 753 | void setIsIntrinsic() { |
371 | 753 | MOZ_ASSERT(isNative()); |
372 | 753 | MOZ_ASSERT(!isIntrinsic()); |
373 | 753 | flags_ |= SELF_HOSTED; |
374 | 753 | } |
375 | | |
376 | 0 | void setArrow() { |
377 | 0 | setKind(Arrow); |
378 | 0 | } |
379 | | |
380 | 0 | void setResolvedLength() { |
381 | 0 | flags_ |= RESOLVED_LENGTH; |
382 | 0 | } |
383 | | |
384 | 0 | void setResolvedName() { |
385 | 0 | flags_ |= RESOLVED_NAME; |
386 | 0 | } |
387 | | |
388 | | // Mark a function as having its 'new' script information cleared. |
389 | 10 | bool wasNewScriptCleared() const { |
390 | 10 | return flags_ & NEW_SCRIPT_CLEARED; |
391 | 10 | } |
392 | 0 | void setNewScriptCleared() { |
393 | 0 | flags_ |= NEW_SCRIPT_CLEARED; |
394 | 0 | } |
395 | | |
396 | 0 | void setAsyncKind(js::FunctionAsyncKind asyncKind) { |
397 | 0 | if (isInterpretedLazy()) { |
398 | 0 | lazyScript()->setAsyncKind(asyncKind); |
399 | 0 | } else { |
400 | 0 | nonLazyScript()->setAsyncKind(asyncKind); |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | | static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun, |
405 | | js::MutableHandleValue v); |
406 | | |
407 | | JSAtom* infallibleGetUnresolvedName(JSContext* cx); |
408 | | |
409 | | static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun, |
410 | | js::MutableHandleString v); |
411 | | |
412 | | static JSLinearString* getBoundFunctionName(JSContext* cx, js::HandleFunction fun); |
413 | | |
414 | 4.64k | JSAtom* explicitName() const { |
415 | 4.64k | return (hasInferredName() || hasGuessedAtom()) ? nullptr : atom_.get(); |
416 | 4.64k | } |
417 | 0 | JSAtom* explicitOrInferredName() const { |
418 | 0 | return hasGuessedAtom() ? nullptr : atom_.get(); |
419 | 0 | } |
420 | | |
421 | 3.25M | void initAtom(JSAtom* atom) { |
422 | 3.25M | MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom)); |
423 | 3.25M | atom_.init(atom); |
424 | 3.25M | } |
425 | | |
426 | 156 | void setAtom(JSAtom* atom) { |
427 | 156 | MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom)); |
428 | 156 | atom_ = atom; |
429 | 156 | } |
430 | | |
431 | 3.81k | JSAtom* displayAtom() const { |
432 | 3.81k | return atom_; |
433 | 3.81k | } |
434 | | |
435 | 79 | void setInferredName(JSAtom* atom) { |
436 | 79 | MOZ_ASSERT(!atom_); |
437 | 79 | MOZ_ASSERT(atom); |
438 | 79 | MOZ_ASSERT(!hasGuessedAtom()); |
439 | 79 | setAtom(atom); |
440 | 79 | flags_ |= HAS_INFERRED_NAME; |
441 | 79 | } |
442 | 6 | void clearInferredName() { |
443 | 6 | MOZ_ASSERT(hasInferredName()); |
444 | 6 | MOZ_ASSERT(atom_); |
445 | 6 | setAtom(nullptr); |
446 | 6 | flags_ &= ~HAS_INFERRED_NAME; |
447 | 6 | } |
448 | 0 | JSAtom* inferredName() const { |
449 | 0 | MOZ_ASSERT(hasInferredName()); |
450 | 0 | MOZ_ASSERT(atom_); |
451 | 0 | return atom_; |
452 | 0 | } |
453 | | |
454 | 14 | void setGuessedAtom(JSAtom* atom) { |
455 | 14 | MOZ_ASSERT(!atom_); |
456 | 14 | MOZ_ASSERT(atom); |
457 | 14 | MOZ_ASSERT(!hasInferredName()); |
458 | 14 | MOZ_ASSERT(!hasGuessedAtom()); |
459 | 14 | MOZ_ASSERT(!isBoundFunction()); |
460 | 14 | setAtom(atom); |
461 | 14 | flags_ |= HAS_GUESSED_ATOM; |
462 | 14 | } |
463 | 0 | void clearGuessedAtom() { |
464 | 0 | MOZ_ASSERT(hasGuessedAtom()); |
465 | 0 | MOZ_ASSERT(!isBoundFunction()); |
466 | 0 | MOZ_ASSERT(atom_); |
467 | 0 | setAtom(nullptr); |
468 | 0 | flags_ &= ~HAS_GUESSED_ATOM; |
469 | 0 | } |
470 | | |
471 | 0 | void setPrefixedBoundFunctionName(JSAtom* atom) { |
472 | 0 | MOZ_ASSERT(!hasBoundFunctionNamePrefix()); |
473 | 0 | MOZ_ASSERT(atom); |
474 | 0 | flags_ |= HAS_BOUND_FUNCTION_NAME_PREFIX; |
475 | 0 | setAtom(atom); |
476 | 0 | } |
477 | | |
478 | | /* uint16_t representation bounds number of call object dynamic slots. */ |
479 | | enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) }; |
480 | | |
481 | | /* |
482 | | * For an interpreted function, accessors for the initial scope object of |
483 | | * activations (stack frames) of the function. |
484 | | */ |
485 | 161 | JSObject* environment() const { |
486 | 161 | MOZ_ASSERT(isInterpreted()); |
487 | 161 | return u.scripted.env_; |
488 | 161 | } |
489 | | |
490 | 1.32k | void setEnvironment(JSObject* obj) { |
491 | 1.32k | MOZ_ASSERT(isInterpreted()); |
492 | 1.32k | *reinterpret_cast<js::GCPtrObject*>(&u.scripted.env_) = obj; |
493 | 1.32k | } |
494 | | |
495 | 1.76k | void initEnvironment(JSObject* obj) { |
496 | 1.76k | MOZ_ASSERT(isInterpreted()); |
497 | 1.76k | reinterpret_cast<js::GCPtrObject*>(&u.scripted.env_)->init(obj); |
498 | 1.76k | } |
499 | | |
500 | 0 | void unsetEnvironment() { |
501 | 0 | setEnvironment(nullptr); |
502 | 0 | } |
503 | | |
504 | | public: |
505 | 131 | static constexpr size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); } |
506 | 0 | static constexpr size_t offsetOfFlags() { return offsetof(JSFunction, flags_); } |
507 | 28 | static size_t offsetOfEnvironment() { return offsetof(JSFunction, u.scripted.env_); } |
508 | 0 | static size_t offsetOfAtom() { return offsetof(JSFunction, atom_); } |
509 | | |
510 | | static bool createScriptForLazilyInterpretedFunction(JSContext* cx, js::HandleFunction fun); |
511 | | void maybeRelazify(JSRuntime* rt); |
512 | | |
513 | | // Function Scripts |
514 | | // |
515 | | // Interpreted functions may either have an explicit JSScript (hasScript()) |
516 | | // or be lazy with sufficient information to construct the JSScript if |
517 | | // necessary (isInterpretedLazy()). |
518 | | // |
519 | | // A lazy function will have a LazyScript if the function came from parsed |
520 | | // source, or nullptr if the function is a clone of a self hosted function. |
521 | | // |
522 | | // There are several methods to get the script of an interpreted function: |
523 | | // |
524 | | // - For all interpreted functions, getOrCreateScript() will get the |
525 | | // JSScript, delazifying the function if necessary. This is the safest to |
526 | | // use, but has extra checks, requires a cx and may trigger a GC. |
527 | | // |
528 | | // - For inlined functions which may have a LazyScript but whose JSScript |
529 | | // is known to exist, existingScript() will get the script and delazify |
530 | | // the function if necessary. If the function should not be delazified, |
531 | | // use existingScriptNonDelazifying(). |
532 | | // |
533 | | // - For functions known to have a JSScript, nonLazyScript() will get it. |
534 | | |
535 | 1.62M | static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) { |
536 | 1.62M | MOZ_ASSERT(fun->isInterpreted()); |
537 | 1.62M | MOZ_ASSERT(cx); |
538 | 1.62M | if (fun->isInterpretedLazy()) { |
539 | 3 | if (!createScriptForLazilyInterpretedFunction(cx, fun)) { |
540 | 0 | return nullptr; |
541 | 0 | } |
542 | 3 | return fun->nonLazyScript(); |
543 | 3 | } |
544 | 1.62M | return fun->nonLazyScript(); |
545 | 1.62M | } |
546 | | |
547 | 0 | JSScript* existingScriptNonDelazifying() const { |
548 | 0 | MOZ_ASSERT(isInterpreted()); |
549 | 0 | if (isInterpretedLazy()) { |
550 | 0 | // Get the script from the canonical function. Ion used the |
551 | 0 | // canonical function to inline the script and because it has |
552 | 0 | // Baseline code it has not been relazified. Note that we can't |
553 | 0 | // use lazyScript->script_ here as it may be null in some cases, |
554 | 0 | // see bug 976536. |
555 | 0 | js::LazyScript* lazy = lazyScript(); |
556 | 0 | JSFunction* fun = lazy->functionNonDelazifying(); |
557 | 0 | MOZ_ASSERT(fun); |
558 | 0 | return fun->nonLazyScript(); |
559 | 0 | } |
560 | 0 | return nonLazyScript(); |
561 | 0 | } |
562 | | |
563 | 0 | JSScript* existingScript() { |
564 | 0 | MOZ_ASSERT(isInterpreted()); |
565 | 0 | if (isInterpretedLazy()) { |
566 | 0 | if (shadowZone()->needsIncrementalBarrier()) { |
567 | 0 | js::LazyScript::writeBarrierPre(lazyScript()); |
568 | 0 | } |
569 | 0 | JSScript* script = existingScriptNonDelazifying(); |
570 | 0 | flags_ &= ~INTERPRETED_LAZY; |
571 | 0 | flags_ |= INTERPRETED; |
572 | 0 | initScript(script); |
573 | 0 | } |
574 | 0 | return nonLazyScript(); |
575 | 0 | } |
576 | | |
577 | | // The state of a JSFunction whose script errored out during bytecode |
578 | | // compilation. Such JSFunctions are only reachable via GC iteration and |
579 | | // not from script. |
580 | | // If u.scripted.s.script_ is non-null, the pointed JSScript is guaranteed |
581 | | // to be complete (see the comment above JSScript::initFromFunctionBox |
582 | | // callsite in JSScript::fullyInitFromEmitter). |
583 | 4.01k | bool hasUncompletedScript() const { |
584 | 4.01k | MOZ_ASSERT(hasScript()); |
585 | 4.01k | return !u.scripted.s.script_; |
586 | 4.01k | } |
587 | | |
588 | 3.56M | JSScript* nonLazyScript() const { |
589 | 3.56M | MOZ_ASSERT(!hasUncompletedScript()); |
590 | 3.56M | return u.scripted.s.script_; |
591 | 3.56M | } |
592 | | |
593 | | static bool getLength(JSContext* cx, js::HandleFunction fun, uint16_t* length); |
594 | | |
595 | 0 | js::LazyScript* lazyScript() const { |
596 | 0 | MOZ_ASSERT(isInterpretedLazy() && u.scripted.s.lazy_); |
597 | 0 | return u.scripted.s.lazy_; |
598 | 0 | } |
599 | | |
600 | 6 | js::LazyScript* lazyScriptOrNull() const { |
601 | 6 | MOZ_ASSERT(isInterpretedLazy()); |
602 | 6 | return u.scripted.s.lazy_; |
603 | 6 | } |
604 | | |
605 | 371 | js::GeneratorKind generatorKind() const { |
606 | 371 | if (!isInterpreted()) { |
607 | 13 | return js::GeneratorKind::NotGenerator; |
608 | 13 | } |
609 | 358 | if (hasScript()) { |
610 | 358 | return nonLazyScript()->generatorKind(); |
611 | 358 | } |
612 | 0 | if (js::LazyScript* lazy = lazyScriptOrNull()) { |
613 | 0 | return lazy->generatorKind(); |
614 | 0 | } |
615 | 0 | MOZ_ASSERT(isSelfHostedBuiltin()); |
616 | 0 | return js::GeneratorKind::NotGenerator; |
617 | 0 | } |
618 | | |
619 | 371 | bool isGenerator() const { return generatorKind() == js::GeneratorKind::Generator; } |
620 | | |
621 | 0 | js::FunctionAsyncKind asyncKind() const { |
622 | 0 | return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind(); |
623 | 0 | } |
624 | | |
625 | 369 | bool isAsync() const { |
626 | 369 | if (isInterpretedLazy()) { |
627 | 0 | return lazyScript()->isAsync(); |
628 | 0 | } |
629 | 369 | if (hasScript()) { |
630 | 356 | return nonLazyScript()->isAsync(); |
631 | 356 | } |
632 | 13 | return false; |
633 | 13 | } |
634 | | |
635 | 1.48k | void setScript(JSScript* script_) { |
636 | 1.48k | mutableScript() = script_; |
637 | 1.48k | } |
638 | | |
639 | 1.65k | void initScript(JSScript* script_) { |
640 | 1.65k | mutableScript().init(script_); |
641 | 1.65k | } |
642 | | |
643 | 3 | void setUnlazifiedScript(JSScript* script) { |
644 | 3 | MOZ_ASSERT(isInterpretedLazy()); |
645 | 3 | if (lazyScriptOrNull()) { |
646 | 0 | // Trigger a pre barrier on the lazy script being overwritten. |
647 | 0 | js::LazyScript::writeBarrierPre(lazyScriptOrNull()); |
648 | 0 | if (!lazyScript()->maybeScript()) { |
649 | 0 | lazyScript()->initScript(script); |
650 | 0 | } |
651 | 0 | } |
652 | 3 | flags_ &= ~INTERPRETED_LAZY; |
653 | 3 | flags_ |= INTERPRETED; |
654 | 3 | initScript(script); |
655 | 3 | } |
656 | | |
657 | 129 | void initLazyScript(js::LazyScript* lazy) { |
658 | 129 | MOZ_ASSERT(isInterpreted()); |
659 | 129 | flags_ &= ~INTERPRETED; |
660 | 129 | flags_ |= INTERPRETED_LAZY; |
661 | 129 | u.scripted.s.lazy_ = lazy; |
662 | 129 | } |
663 | | |
664 | 4.86M | JSNative native() const { |
665 | 4.86M | MOZ_ASSERT(isNative()); |
666 | 4.86M | return u.native.func_; |
667 | 4.86M | } |
668 | | |
669 | 36 | JSNative maybeNative() const { |
670 | 36 | return isInterpreted() ? nullptr : native(); |
671 | 36 | } |
672 | | |
673 | 3.24M | void initNative(js::Native native, const JSJitInfo* jitInfo) { |
674 | 3.24M | MOZ_ASSERT(isNativeWithCppEntry()); |
675 | 3.24M | MOZ_ASSERT_IF(jitInfo, isBuiltinNative()); |
676 | 3.24M | MOZ_ASSERT(native); |
677 | 3.24M | u.native.func_ = native; |
678 | 3.24M | u.native.extra.jitInfo_ = jitInfo; |
679 | 3.24M | } |
680 | 4.87M | bool hasJitInfo() const { |
681 | 4.87M | return isBuiltinNative() && u.native.extra.jitInfo_; |
682 | 4.87M | } |
683 | 62 | const JSJitInfo* jitInfo() const { |
684 | 62 | MOZ_ASSERT(hasJitInfo()); |
685 | 62 | return u.native.extra.jitInfo_; |
686 | 62 | } |
687 | 283 | void setJitInfo(const JSJitInfo* data) { |
688 | 283 | MOZ_ASSERT(isBuiltinNative()); |
689 | 283 | u.native.extra.jitInfo_ = data; |
690 | 283 | } |
691 | | |
692 | | // Wasm natives are optimized and have a jit entry. |
693 | 0 | void initWasmNative(js::Native native) { |
694 | 0 | MOZ_ASSERT(isNativeWithJitEntry()); |
695 | 0 | MOZ_ASSERT(native); |
696 | 0 | u.native.func_ = native; |
697 | 0 | u.native.extra.wasmJitEntry_ = nullptr; |
698 | 0 | } |
699 | 0 | void setWasmJitEntry(void** entry) { |
700 | 0 | MOZ_ASSERT(isNativeWithJitEntry()); |
701 | 0 | MOZ_ASSERT(entry); |
702 | 0 | MOZ_ASSERT(!u.native.extra.wasmJitEntry_); |
703 | 0 | u.native.extra.wasmJitEntry_ = entry; |
704 | 0 | } |
705 | 0 | void** wasmJitEntry() const { |
706 | 0 | MOZ_ASSERT(isNativeWithJitEntry()); |
707 | 0 | MOZ_ASSERT(u.native.extra.wasmJitEntry_); |
708 | 0 | return u.native.extra.wasmJitEntry_; |
709 | 0 | } |
710 | | |
711 | | // AsmJS functions store the func index in the jitinfo slot, since these |
712 | | // don't have a jit info associated. |
713 | 0 | void setAsmJSIndex(uint32_t funcIndex) { |
714 | 0 | MOZ_ASSERT(isAsmJSNative()); |
715 | 0 | MOZ_ASSERT(!isWasmOptimized()); |
716 | 0 | MOZ_ASSERT(!u.native.extra.asmJSFuncIndex_); |
717 | 0 | u.native.extra.asmJSFuncIndex_ = funcIndex; |
718 | 0 | } |
719 | 0 | uint32_t asmJSFuncIndex() const { |
720 | 0 | MOZ_ASSERT(isAsmJSNative()); |
721 | 0 | MOZ_ASSERT(!isWasmOptimized()); |
722 | 0 | return u.native.extra.asmJSFuncIndex_; |
723 | 0 | } |
724 | | |
725 | | bool isDerivedClassConstructor(); |
726 | | |
727 | 1 | static unsigned offsetOfNative() { |
728 | 1 | return offsetof(JSFunction, u.native.func_); |
729 | 1 | } |
730 | 46 | static unsigned offsetOfScript() { |
731 | 46 | static_assert(offsetof(U, scripted.s.script_) == offsetof(U, native.extra.wasmJitEntry_), |
732 | 46 | "scripted.s.script_ must be at the same offset as native.extra.wasmJitEntry_"); |
733 | 46 | return offsetof(JSFunction, u.scripted.s.script_); |
734 | 46 | } |
735 | 0 | static unsigned offsetOfNativeOrEnv() { |
736 | 0 | static_assert(offsetof(U, native.func_) == offsetof(U, scripted.env_), |
737 | 0 | "U.native.func_ must be at the same offset as U.scripted.env_"); |
738 | 0 | return offsetOfNative(); |
739 | 0 | } |
740 | 0 | static unsigned offsetOfScriptOrLazyScript() { |
741 | 0 | static_assert(offsetof(U, scripted.s.script_) == offsetof(U, scripted.s.lazy_), |
742 | 0 | "U.scripted.s.script_ must be at the same offset as lazy_"); |
743 | 0 | return offsetof(JSFunction, u.scripted.s.script_); |
744 | 0 | } |
745 | | |
746 | 0 | static unsigned offsetOfJitInfo() { |
747 | 0 | return offsetof(JSFunction, u.native.extra.jitInfo_); |
748 | 0 | } |
749 | | |
750 | | inline void trace(JSTracer* trc); |
751 | | |
752 | | /* Bound function accessors. */ |
753 | | |
754 | | JSObject* getBoundFunctionTarget() const; |
755 | | const js::Value& getBoundFunctionThis() const; |
756 | | const js::Value& getBoundFunctionArgument(unsigned which) const; |
757 | | size_t getBoundFunctionArgumentCount() const; |
758 | | |
759 | | /* |
760 | | * Used to mark bound functions as such and make them constructible if the |
761 | | * target is. Also assigns the prototype and sets the name and correct length. |
762 | | */ |
763 | | static bool finishBoundFunctionInit(JSContext* cx, js::HandleFunction bound, |
764 | | js::HandleObject targetObj, int32_t argCount); |
765 | | |
766 | | private: |
767 | 3.13k | js::GCPtrScript& mutableScript() { |
768 | 3.13k | MOZ_ASSERT(hasScript()); |
769 | 3.13k | return *(js::GCPtrScript*)&u.scripted.s.script_; |
770 | 3.13k | } |
771 | | |
772 | | inline js::FunctionExtended* toExtended(); |
773 | | inline const js::FunctionExtended* toExtended() const; |
774 | | |
775 | | public: |
776 | 8.40k | inline bool isExtended() const { |
777 | 8.40k | bool extended = !!(flags() & EXTENDED); |
778 | 8.40k | MOZ_ASSERT_IF(isTenured(), |
779 | 8.40k | extended == (asTenured().getAllocKind() == js::gc::AllocKind::FUNCTION_EXTENDED)); |
780 | 8.40k | return extended; |
781 | 8.40k | } |
782 | | |
783 | | /* |
784 | | * Accessors for data stored in extended functions. Use setExtendedSlot if |
785 | | * the function has already been initialized. Otherwise use |
786 | | * initExtendedSlot. |
787 | | */ |
788 | | inline void initializeExtended(); |
789 | | inline void initExtendedSlot(size_t which, const js::Value& val); |
790 | | inline void setExtendedSlot(size_t which, const js::Value& val); |
791 | | inline const js::Value& getExtendedSlot(size_t which) const; |
792 | | |
793 | | /* Constructs a new type for the function if necessary. */ |
794 | | static bool setTypeForScriptedFunction(JSContext* cx, js::HandleFunction fun, |
795 | | bool singleton = false); |
796 | | |
797 | | /* GC support. */ |
798 | 142 | js::gc::AllocKind getAllocKind() const { |
799 | 142 | static_assert(js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED, |
800 | 142 | "extended/non-extended AllocKinds have to be different " |
801 | 142 | "for getAllocKind() to have a reason to exist"); |
802 | 142 | |
803 | 142 | js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION; |
804 | 142 | if (isExtended()) { |
805 | 27 | kind = js::gc::AllocKind::FUNCTION_EXTENDED; |
806 | 27 | } |
807 | 142 | MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind()); |
808 | 142 | return kind; |
809 | 142 | } |
810 | | }; |
811 | | |
812 | | static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function), |
813 | | "shadow interface must match actual interface"); |
814 | | |
815 | | extern JSString* |
816 | | fun_toStringHelper(JSContext* cx, js::HandleObject obj, bool isToSource); |
817 | | |
818 | | namespace js { |
819 | | |
820 | | extern bool |
821 | | Function(JSContext* cx, unsigned argc, Value* vp); |
822 | | |
823 | | extern bool |
824 | | Generator(JSContext* cx, unsigned argc, Value* vp); |
825 | | |
826 | | extern bool |
827 | | AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp); |
828 | | |
829 | | extern bool |
830 | | AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp); |
831 | | |
832 | | // If enclosingEnv is null, the function will have a null environment() |
833 | | // (yes, null, not the global). In all cases, the global will be used as the |
834 | | // parent. |
835 | | |
836 | | extern JSFunction* |
837 | | NewFunctionWithProto(JSContext* cx, JSNative native, unsigned nargs, |
838 | | JSFunction::Flags flags, HandleObject enclosingEnv, HandleAtom atom, |
839 | | HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, |
840 | | NewObjectKind newKind = GenericObject); |
841 | | |
842 | | // Allocate a new function backed by a JSNative. Note that by default this |
843 | | // creates a singleton object. |
844 | | inline JSFunction* |
845 | | NewNativeFunction(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom, |
846 | | gc::AllocKind allocKind = gc::AllocKind::FUNCTION, |
847 | | NewObjectKind newKind = SingletonObject, |
848 | | JSFunction::Flags flags = JSFunction::NATIVE_FUN) |
849 | 3.24M | { |
850 | 3.24M | MOZ_ASSERT(native); |
851 | 3.24M | return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr, allocKind, |
852 | 3.24M | newKind); |
853 | 3.24M | } |
854 | | |
855 | | // Allocate a new constructor backed by a JSNative. Note that by default this |
856 | | // creates a singleton object. |
857 | | inline JSFunction* |
858 | | NewNativeConstructor(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom, |
859 | | gc::AllocKind allocKind = gc::AllocKind::FUNCTION, |
860 | | NewObjectKind newKind = SingletonObject, |
861 | | JSFunction::Flags flags = JSFunction::NATIVE_CTOR) |
862 | 25 | { |
863 | 25 | MOZ_ASSERT(native); |
864 | 25 | MOZ_ASSERT(flags & JSFunction::NATIVE_CTOR); |
865 | 25 | return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr, allocKind, |
866 | 25 | newKind); |
867 | 25 | } |
868 | | |
869 | | // Allocate a new scripted function. If enclosingEnv is null, the |
870 | | // global will be used. In all cases the parent of the resulting object will be |
871 | | // the global. |
872 | | extern JSFunction* |
873 | | NewScriptedFunction(JSContext* cx, unsigned nargs, JSFunction::Flags flags, |
874 | | HandleAtom atom, HandleObject proto = nullptr, |
875 | | gc::AllocKind allocKind = gc::AllocKind::FUNCTION, |
876 | | NewObjectKind newKind = GenericObject, |
877 | | HandleObject enclosingEnv = nullptr); |
878 | | extern JSAtom* |
879 | | IdToFunctionName(JSContext* cx, HandleId id, |
880 | | FunctionPrefixKind prefixKind = FunctionPrefixKind::None); |
881 | | |
882 | | extern bool |
883 | | SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name, |
884 | | FunctionPrefixKind prefixKind); |
885 | | |
886 | | extern JSFunction* |
887 | | DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native, |
888 | | unsigned nargs, unsigned flags, |
889 | | gc::AllocKind allocKind = gc::AllocKind::FUNCTION); |
890 | | |
891 | | extern bool |
892 | | fun_toString(JSContext* cx, unsigned argc, Value* vp); |
893 | | |
894 | | struct WellKnownSymbols; |
895 | | |
896 | | extern bool |
897 | | FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols); |
898 | | |
899 | | extern bool |
900 | | fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp); |
901 | | |
902 | | extern void |
903 | | ThrowTypeErrorBehavior(JSContext* cx); |
904 | | |
905 | | /* |
906 | | * Function extended with reserved slots for use by various kinds of functions. |
907 | | * Most functions do not have these extensions, but enough do that efficient |
908 | | * storage is required (no malloc'ed reserved slots). |
909 | | */ |
910 | | class FunctionExtended : public JSFunction |
911 | | { |
912 | | public: |
913 | | static const unsigned NUM_EXTENDED_SLOTS = 2; |
914 | | |
915 | | /* Arrow functions store their lexical new.target in the first extended slot. */ |
916 | | static const unsigned ARROW_NEWTARGET_SLOT = 0; |
917 | | |
918 | | static const unsigned METHOD_HOMEOBJECT_SLOT = 0; |
919 | | |
920 | | /* |
921 | | * Exported asm.js/wasm functions store their WasmInstanceObject in the |
922 | | * first slot. |
923 | | */ |
924 | | static const unsigned WASM_INSTANCE_SLOT = 0; |
925 | | |
926 | | /* |
927 | | * wasm/asm.js exported functions store the wasm::TlsData pointer of their |
928 | | * instance. |
929 | | */ |
930 | | static const unsigned WASM_TLSDATA_SLOT = 1; |
931 | | |
932 | | /* |
933 | | * asm.js module functions store their WasmModuleObject in the first slot. |
934 | | */ |
935 | | static const unsigned ASMJS_MODULE_SLOT = 0; |
936 | | |
937 | | |
938 | 0 | static inline size_t offsetOfExtendedSlot(unsigned which) { |
939 | 0 | MOZ_ASSERT(which < NUM_EXTENDED_SLOTS); |
940 | 0 | return offsetof(FunctionExtended, extendedSlots) + which * sizeof(GCPtrValue); |
941 | 0 | } |
942 | 0 | static inline size_t offsetOfArrowNewTargetSlot() { |
943 | 0 | return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT); |
944 | 0 | } |
945 | 0 | static inline size_t offsetOfMethodHomeObjectSlot() { |
946 | 0 | return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT); |
947 | 0 | } |
948 | | |
949 | | private: |
950 | | friend class JSFunction; |
951 | | |
952 | | /* Reserved slots available for storage by particular native functions. */ |
953 | | GCPtrValue extendedSlots[NUM_EXTENDED_SLOTS]; |
954 | | }; |
955 | | |
956 | | extern bool |
957 | | CanReuseScriptForClone(JS::Realm* realm, HandleFunction fun, HandleObject newParent); |
958 | | |
959 | | extern JSFunction* |
960 | | CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent, |
961 | | gc::AllocKind kind = gc::AllocKind::FUNCTION, |
962 | | NewObjectKind newKindArg = GenericObject, |
963 | | HandleObject proto = nullptr); |
964 | | |
965 | | // Functions whose scripts are cloned are always given singleton types. |
966 | | extern JSFunction* |
967 | | CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent, |
968 | | HandleScope newScope, |
969 | | gc::AllocKind kind = gc::AllocKind::FUNCTION, |
970 | | HandleObject proto = nullptr); |
971 | | |
972 | | extern JSFunction* |
973 | | CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun); |
974 | | |
975 | | extern JSFunction* |
976 | | CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun); |
977 | | |
978 | | } // namespace js |
979 | | |
980 | | inline js::FunctionExtended* |
981 | | JSFunction::toExtended() |
982 | 16.2M | { |
983 | 16.2M | MOZ_ASSERT(isExtended()); |
984 | 16.2M | return static_cast<js::FunctionExtended*>(this); |
985 | 16.2M | } |
986 | | |
987 | | inline const js::FunctionExtended* |
988 | | JSFunction::toExtended() const |
989 | 12.9M | { |
990 | 12.9M | MOZ_ASSERT(isExtended()); |
991 | 12.9M | return static_cast<const js::FunctionExtended*>(this); |
992 | 12.9M | } |
993 | | |
994 | | inline void |
995 | | JSFunction::initializeExtended() |
996 | 3.24M | { |
997 | 3.24M | MOZ_ASSERT(isExtended()); |
998 | 3.24M | |
999 | 3.24M | MOZ_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2); |
1000 | 3.24M | toExtended()->extendedSlots[0].init(js::UndefinedValue()); |
1001 | 3.24M | toExtended()->extendedSlots[1].init(js::UndefinedValue()); |
1002 | 3.24M | } |
1003 | | |
1004 | | inline void |
1005 | | JSFunction::initExtendedSlot(size_t which, const js::Value& val) |
1006 | 54 | { |
1007 | 54 | MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); |
1008 | 54 | MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment())); |
1009 | 54 | toExtended()->extendedSlots[which].init(val); |
1010 | 54 | } |
1011 | | |
1012 | | inline void |
1013 | | JSFunction::setExtendedSlot(size_t which, const js::Value& val) |
1014 | 6.49M | { |
1015 | 6.49M | MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); |
1016 | 6.49M | MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment())); |
1017 | 6.49M | toExtended()->extendedSlots[which] = val; |
1018 | 6.49M | } |
1019 | | |
1020 | | inline const js::Value& |
1021 | | JSFunction::getExtendedSlot(size_t which) const |
1022 | 12.9M | { |
1023 | 12.9M | MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); |
1024 | 12.9M | return toExtended()->extendedSlots[which]; |
1025 | 12.9M | } |
1026 | | |
1027 | | namespace js { |
1028 | | |
1029 | | JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource); |
1030 | | |
1031 | | template<XDRMode mode> |
1032 | | XDRResult |
1033 | | XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope, |
1034 | | HandleScriptSourceObject sourceObject, MutableHandleFunction objp); |
1035 | | |
1036 | | /* |
1037 | | * Report an error that call.thisv is not compatible with the specified class, |
1038 | | * assuming that the method (clasp->name).prototype.<name of callee function> |
1039 | | * is what was called. |
1040 | | */ |
1041 | | extern void |
1042 | | ReportIncompatibleMethod(JSContext* cx, const CallArgs& args, const Class* clasp); |
1043 | | |
1044 | | /* |
1045 | | * Report an error that call.thisv is not an acceptable this for the callee |
1046 | | * function. |
1047 | | */ |
1048 | | extern void |
1049 | | ReportIncompatible(JSContext* cx, const CallArgs& args); |
1050 | | |
1051 | | extern const JSFunctionSpec function_methods[]; |
1052 | | extern const JSFunctionSpec function_selfhosted_methods[]; |
1053 | | |
1054 | | extern bool |
1055 | | fun_apply(JSContext* cx, unsigned argc, Value* vp); |
1056 | | |
1057 | | extern bool |
1058 | | fun_call(JSContext* cx, unsigned argc, Value* vp); |
1059 | | |
1060 | | } /* namespace js */ |
1061 | | |
1062 | | #ifdef DEBUG |
1063 | | namespace JS { |
1064 | | namespace detail { |
1065 | | |
1066 | | JS_PUBLIC_API(void) |
1067 | | CheckIsValidConstructible(const Value& calleev); |
1068 | | |
1069 | | } // namespace detail |
1070 | | } // namespace JS |
1071 | | #endif |
1072 | | |
1073 | | #endif /* vm_JSFunction_h */ |