Line data Source code
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 jsfun_h
8 : #define jsfun_h
9 :
10 : /*
11 : * JS function definitions.
12 : */
13 :
14 : #include "jsobj.h"
15 : #include "jsscript.h"
16 : #include "jstypes.h"
17 :
18 : namespace js {
19 :
20 : class FunctionExtended;
21 :
22 : typedef JSNative Native;
23 : } // namespace js
24 :
25 : struct JSAtomState;
26 :
27 : static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
28 : static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
29 : static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
30 :
31 : static const char FunctionConstructorMedialSigils[] = ") {\n";
32 : static const char FunctionConstructorFinalBrace[] = "\n}";
33 :
34 : enum class FunctionPrefixKind {
35 : None,
36 : Get,
37 : Set
38 : };
39 :
40 : class JSFunction : public js::NativeObject
41 : {
42 : public:
43 : static const js::Class class_;
44 :
45 : enum FunctionKind {
46 : NormalFunction = 0,
47 : Arrow, /* ES6 '(args) => body' syntax */
48 : Method, /* ES6 MethodDefinition */
49 : ClassConstructor,
50 : Getter,
51 : Setter,
52 : AsmJS, /* function is an asm.js module or exported function */
53 : FunctionKindLimit
54 : };
55 :
56 : enum Flags {
57 : INTERPRETED = 0x0001, /* function has a JSScript and environment. */
58 : CONSTRUCTOR = 0x0002, /* function that can be called as a constructor */
59 : EXTENDED = 0x0004, /* structure is FunctionExtended */
60 : BOUND_FUN = 0x0008, /* function was created with Function.prototype.bind. */
61 : HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a
62 : name was guessed for it anyway */
63 : HAS_BOUND_FUNCTION_NAME_PREFIX = 0x0020, /* bound functions reuse the HAS_GUESSED_ATOM
64 : flag to track if atom_ already contains the
65 : "bound " function name prefix */
66 : LAMBDA = 0x0040, /* function comes from a FunctionExpression, ArrowFunction, or
67 : Function() call (not a FunctionDeclaration or nonstandard
68 : function-statement) */
69 : SELF_HOSTED = 0x0080, /* function is self-hosted builtin and must not be
70 : decompilable nor constructible. */
71 : HAS_COMPILE_TIME_NAME = 0x0100, /* function had no explicit name, but a
72 : name was set by SetFunctionName
73 : at compile time */
74 : INTERPRETED_LAZY = 0x0200, /* function is interpreted but doesn't have a script yet */
75 : RESOLVED_LENGTH = 0x0400, /* f.length has been resolved (see fun_resolve). */
76 : RESOLVED_NAME = 0x0800, /* f.name has been resolved (see fun_resolve). */
77 :
78 : FUNCTION_KIND_SHIFT = 13,
79 : FUNCTION_KIND_MASK = 0x7 << FUNCTION_KIND_SHIFT,
80 :
81 : ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
82 : ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
83 : METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
84 : CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
85 : GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
86 : SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
87 :
88 : /* Derived Flags values for convenience: */
89 : NATIVE_FUN = 0,
90 : NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
91 : NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
92 : ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
93 : ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
94 : INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
95 : INTERPRETED_METHOD_GENERATOR_OR_ASYNC = INTERPRETED | METHOD_KIND,
96 : INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
97 : INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
98 : INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
99 : INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
100 : INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
101 : INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = INTERPRETED | LAMBDA,
102 : INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
103 : INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED,
104 : NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
105 :
106 : STABLE_ACROSS_CLONES = CONSTRUCTOR | LAMBDA | SELF_HOSTED | HAS_COMPILE_TIME_NAME |
107 : FUNCTION_KIND_MASK
108 : };
109 :
110 : static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
111 : "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
112 : static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
113 : "FunctionKind doesn't fit into flags_");
114 :
115 : private:
116 : uint16_t nargs_; /* number of formal arguments
117 : (including defaults and the rest parameter unlike f.length) */
118 : uint16_t flags_; /* bitfield composed of the above Flags enum, as well as the kind */
119 : union U {
120 : class Native {
121 : friend class JSFunction;
122 : js::Native native; /* native method pointer or null */
123 : const JSJitInfo* jitinfo; /* Information about this function to be
124 : used by the JIT;
125 : use the accessor! */
126 : } n;
127 : struct Scripted {
128 : union {
129 : JSScript* script_; /* interpreted bytecode descriptor or null;
130 : use the accessor! */
131 : js::LazyScript* lazy_; /* lazily compiled script, or nullptr */
132 : } s;
133 : JSObject* env_; /* environment for new activations */
134 : } i;
135 : void* nativeOrScript;
136 : } u;
137 : js::GCPtrAtom atom_; /* name for diagnostics and decompiling */
138 :
139 : public:
140 : /* Call objects must be created for each invocation of this function. */
141 26949 : bool needsCallObject() const {
142 26949 : MOZ_ASSERT(!isInterpretedLazy());
143 :
144 26949 : if (isNative())
145 0 : return false;
146 :
147 : // Note: this should be kept in sync with
148 : // FunctionBox::needsCallObjectRegardlessOfBindings().
149 26949 : MOZ_ASSERT_IF(nonLazyScript()->funHasExtensibleScope() ||
150 : nonLazyScript()->needsHomeObject() ||
151 : nonLazyScript()->isDerivedClassConstructor() ||
152 : isStarGenerator() ||
153 : isLegacyGenerator() ||
154 : isAsync(),
155 : nonLazyScript()->bodyScope()->hasEnvironment());
156 :
157 26949 : return nonLazyScript()->bodyScope()->hasEnvironment();
158 : }
159 :
160 : bool needsExtraBodyVarEnvironment() const;
161 : bool needsNamedLambdaEnvironment() const;
162 :
163 21896 : bool needsFunctionEnvironmentObjects() const {
164 21896 : return needsCallObject() || needsNamedLambdaEnvironment();
165 : }
166 :
167 9670 : bool needsSomeEnvironmentObject() const {
168 9670 : return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment();
169 : }
170 :
171 140717 : size_t nargs() const {
172 140717 : return nargs_;
173 : }
174 :
175 2810965 : uint16_t flags() const {
176 2810965 : return flags_;
177 : }
178 :
179 164955 : FunctionKind kind() const {
180 164955 : return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> FUNCTION_KIND_SHIFT);
181 : }
182 :
183 : /* A function can be classified as either native (C++) or interpreted (JS): */
184 758960 : bool isInterpreted() const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
185 284256 : bool isNative() const { return !isInterpreted(); }
186 :
187 15960 : bool isConstructor() const { return flags() & CONSTRUCTOR; }
188 :
189 : /* Possible attributes of a native function: */
190 2124 : bool isAsmJSNative() const { return kind() == AsmJS; }
191 :
192 : /* Possible attributes of an interpreted function: */
193 23225 : bool isBoundFunction() const { return flags() & BOUND_FUN; }
194 57875 : bool hasCompileTimeName() const { return flags() & HAS_COMPILE_TIME_NAME; }
195 77169 : bool hasGuessedAtom() const {
196 : static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX,
197 : "HAS_GUESSED_ATOM is unused for bound functions");
198 77169 : return (flags() & (HAS_GUESSED_ATOM | BOUND_FUN)) == HAS_GUESSED_ATOM;
199 : }
200 6 : bool hasBoundFunctionNamePrefix() const {
201 : static_assert(HAS_BOUND_FUNCTION_NAME_PREFIX == HAS_GUESSED_ATOM,
202 : "HAS_BOUND_FUNCTION_NAME_PREFIX is only used for bound functions");
203 6 : MOZ_ASSERT(isBoundFunction());
204 6 : return flags() & HAS_BOUND_FUNCTION_NAME_PREFIX;
205 : }
206 49615 : bool isLambda() const { return flags() & LAMBDA; }
207 312751 : bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
208 1022183 : bool hasScript() const { return flags() & INTERPRETED; }
209 :
210 : bool infallibleIsDefaultClassConstructor(JSContext* cx) const;
211 :
212 : // Arrow functions store their lexical new.target in the first extended slot.
213 71181 : bool isArrow() const { return kind() == Arrow; }
214 : // Every class-constructor is also a method.
215 7945 : bool isMethod() const { return kind() == Method || kind() == ClassConstructor; }
216 70327 : bool isClassConstructor() const { return kind() == ClassConstructor; }
217 :
218 4578 : bool isGetter() const { return kind() == Getter; }
219 4177 : bool isSetter() const { return kind() == Setter; }
220 :
221 6539 : bool allowSuperProperty() const {
222 6539 : return isMethod() || isGetter() || isSetter();
223 : }
224 :
225 1402 : bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; }
226 1450 : bool hasResolvedName() const { return flags() & RESOLVED_NAME; }
227 :
228 31987 : bool isSelfHostedOrIntrinsic() const { return flags() & SELF_HOSTED; }
229 30918 : bool isSelfHostedBuiltin() const { return isSelfHostedOrIntrinsic() && !isNative(); }
230 831 : bool isIntrinsic() const { return isSelfHostedOrIntrinsic() && isNative(); }
231 :
232 2094 : bool hasJITCode() const {
233 2094 : if (!hasScript())
234 8 : return false;
235 :
236 2086 : return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
237 : }
238 :
239 : /* Compound attributes: */
240 2599 : bool isBuiltin() const {
241 2599 : return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
242 : }
243 :
244 49611 : bool isNamedLambda() const {
245 49611 : return isLambda() && displayAtom() && !hasCompileTimeName() && !hasGuessedAtom();
246 : }
247 :
248 0 : bool hasLexicalThis() const {
249 0 : return isArrow() || nonLazyScript()->isGeneratorExp();
250 : }
251 :
252 : bool isBuiltinFunctionConstructor();
253 : bool needsPrototypeProperty();
254 :
255 : /* Returns the strictness of this function, which must be interpreted. */
256 201 : bool strict() const {
257 201 : MOZ_ASSERT(isInterpreted());
258 201 : return isInterpretedLazy() ? lazyScript()->strict() : nonLazyScript()->strict();
259 : }
260 :
261 161524 : void setFlags(uint16_t flags) {
262 161524 : this->flags_ = flags;
263 161524 : }
264 3 : void setKind(FunctionKind kind) {
265 3 : this->flags_ &= ~FUNCTION_KIND_MASK;
266 3 : this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
267 3 : }
268 :
269 : // Make the function constructible.
270 216 : void setIsConstructor() {
271 216 : MOZ_ASSERT(!isConstructor());
272 216 : MOZ_ASSERT(isSelfHostedBuiltin());
273 216 : flags_ |= CONSTRUCTOR;
274 216 : }
275 :
276 3 : void setIsClassConstructor() {
277 3 : MOZ_ASSERT(!isClassConstructor());
278 3 : MOZ_ASSERT(isConstructor());
279 :
280 3 : setKind(ClassConstructor);
281 3 : }
282 :
283 : // Can be called multiple times by the parser.
284 122443 : void setArgCount(uint16_t nargs) {
285 122443 : this->nargs_ = nargs;
286 122443 : }
287 :
288 330 : void setIsBoundFunction() {
289 330 : MOZ_ASSERT(!isBoundFunction());
290 330 : flags_ |= BOUND_FUN;
291 330 : }
292 :
293 21248 : void setIsSelfHostedBuiltin() {
294 21248 : MOZ_ASSERT(isInterpreted());
295 21248 : MOZ_ASSERT(!isSelfHostedBuiltin());
296 21248 : flags_ |= SELF_HOSTED;
297 : // Self-hosted functions should not be constructable.
298 21248 : flags_ &= ~CONSTRUCTOR;
299 21248 : }
300 831 : void setIsIntrinsic() {
301 831 : MOZ_ASSERT(isNative());
302 831 : MOZ_ASSERT(!isIntrinsic());
303 831 : flags_ |= SELF_HOSTED;
304 831 : }
305 :
306 : void setArrow() {
307 : setKind(Arrow);
308 : }
309 :
310 371 : void setResolvedLength() {
311 371 : flags_ |= RESOLVED_LENGTH;
312 371 : }
313 :
314 382 : void setResolvedName() {
315 382 : flags_ |= RESOLVED_NAME;
316 382 : }
317 :
318 : void setAsyncKind(js::FunctionAsyncKind asyncKind) {
319 : if (isInterpretedLazy())
320 : lazyScript()->setAsyncKind(asyncKind);
321 : else
322 : nonLazyScript()->setAsyncKind(asyncKind);
323 : }
324 :
325 : static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
326 : js::MutableHandleValue v);
327 :
328 : static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun,
329 : js::MutableHandleAtom v);
330 :
331 45971 : JSAtom* explicitName() const {
332 45971 : return (hasCompileTimeName() || hasGuessedAtom()) ? nullptr : atom_.get();
333 : }
334 725 : JSAtom* explicitOrCompileTimeName() const {
335 725 : return hasGuessedAtom() ? nullptr : atom_.get();
336 : }
337 :
338 117543 : void initAtom(JSAtom* atom) {
339 117543 : MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
340 117546 : atom_.init(atom);
341 117552 : }
342 :
343 393 : void setAtom(JSAtom* atom) {
344 393 : MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
345 393 : atom_ = atom;
346 393 : }
347 :
348 69595 : JSAtom* displayAtom() const {
349 69595 : return atom_;
350 : }
351 :
352 389 : void setCompileTimeName(JSAtom* atom) {
353 389 : MOZ_ASSERT(!atom_);
354 389 : MOZ_ASSERT(atom);
355 389 : MOZ_ASSERT(!hasGuessedAtom());
356 389 : MOZ_ASSERT(!isClassConstructor());
357 389 : MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
358 389 : atom_ = atom;
359 389 : flags_ |= HAS_COMPILE_TIME_NAME;
360 389 : }
361 10 : JSAtom* compileTimeName() const {
362 10 : MOZ_ASSERT(hasCompileTimeName());
363 10 : MOZ_ASSERT(atom_);
364 10 : return atom_;
365 : }
366 :
367 683 : void setGuessedAtom(JSAtom* atom) {
368 683 : MOZ_ASSERT(!atom_);
369 683 : MOZ_ASSERT(atom);
370 683 : MOZ_ASSERT(!hasCompileTimeName());
371 683 : MOZ_ASSERT(!hasGuessedAtom());
372 683 : MOZ_ASSERT(!isBoundFunction());
373 683 : MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
374 683 : atom_ = atom;
375 683 : flags_ |= HAS_GUESSED_ATOM;
376 683 : }
377 6 : void clearGuessedAtom() {
378 6 : MOZ_ASSERT(hasGuessedAtom());
379 6 : MOZ_ASSERT(!isBoundFunction());
380 6 : MOZ_ASSERT(atom_);
381 6 : atom_ = nullptr;
382 6 : flags_ &= ~HAS_GUESSED_ATOM;
383 6 : }
384 :
385 3 : void setPrefixedBoundFunctionName(JSAtom* atom) {
386 3 : MOZ_ASSERT(!hasBoundFunctionNamePrefix());
387 3 : MOZ_ASSERT(atom);
388 3 : flags_ |= HAS_BOUND_FUNCTION_NAME_PREFIX;
389 3 : atom_ = atom;
390 3 : }
391 :
392 : /* uint16_t representation bounds number of call object dynamic slots. */
393 : enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
394 :
395 : /*
396 : * For an interpreted function, accessors for the initial scope object of
397 : * activations (stack frames) of the function.
398 : */
399 13720 : JSObject* environment() const {
400 13720 : MOZ_ASSERT(isInterpreted());
401 13720 : return u.i.env_;
402 : }
403 :
404 1411 : void setEnvironment(JSObject* obj) {
405 1411 : MOZ_ASSERT(isInterpreted());
406 1411 : *reinterpret_cast<js::GCPtrObject*>(&u.i.env_) = obj;
407 1411 : }
408 :
409 58922 : void initEnvironment(JSObject* obj) {
410 58922 : MOZ_ASSERT(isInterpreted());
411 58922 : reinterpret_cast<js::GCPtrObject*>(&u.i.env_)->init(obj);
412 58923 : }
413 :
414 : void unsetEnvironment() {
415 : setEnvironment(nullptr);
416 : }
417 :
418 : public:
419 383 : static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
420 105 : static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
421 639 : static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
422 10 : static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
423 :
424 : static bool createScriptForLazilyInterpretedFunction(JSContext* cx, js::HandleFunction fun);
425 : void maybeRelazify(JSRuntime* rt);
426 :
427 : // Function Scripts
428 : //
429 : // Interpreted functions may either have an explicit JSScript (hasScript())
430 : // or be lazy with sufficient information to construct the JSScript if
431 : // necessary (isInterpretedLazy()).
432 : //
433 : // A lazy function will have a LazyScript if the function came from parsed
434 : // source, or nullptr if the function is a clone of a self hosted function.
435 : //
436 : // There are several methods to get the script of an interpreted function:
437 : //
438 : // - For all interpreted functions, getOrCreateScript() will get the
439 : // JSScript, delazifying the function if necessary. This is the safest to
440 : // use, but has extra checks, requires a cx and may trigger a GC.
441 : //
442 : // - For inlined functions which may have a LazyScript but whose JSScript
443 : // is known to exist, existingScript() will get the script and delazify
444 : // the function if necessary. If the function should not be delazified,
445 : // use existingScriptNonDelazifying().
446 : //
447 : // - For functions known to have a JSScript, nonLazyScript() will get it.
448 :
449 30198 : static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) {
450 30198 : MOZ_ASSERT(fun->isInterpreted());
451 30198 : MOZ_ASSERT(cx);
452 30198 : if (fun->isInterpretedLazy()) {
453 2249 : if (!createScriptForLazilyInterpretedFunction(cx, fun))
454 0 : return nullptr;
455 2249 : return fun->nonLazyScript();
456 : }
457 27949 : return fun->nonLazyScript();
458 : }
459 :
460 4700 : JSScript* existingScriptNonDelazifying() const {
461 4700 : MOZ_ASSERT(isInterpreted());
462 4700 : if (isInterpretedLazy()) {
463 : // Get the script from the canonical function. Ion used the
464 : // canonical function to inline the script and because it has
465 : // Baseline code it has not been relazified. Note that we can't
466 : // use lazyScript->script_ here as it may be null in some cases,
467 : // see bug 976536.
468 0 : js::LazyScript* lazy = lazyScript();
469 0 : JSFunction* fun = lazy->functionNonDelazifying();
470 0 : MOZ_ASSERT(fun);
471 0 : return fun->nonLazyScript();
472 : }
473 4700 : return nonLazyScript();
474 : }
475 :
476 0 : JSScript* existingScript() {
477 0 : MOZ_ASSERT(isInterpreted());
478 0 : if (isInterpretedLazy()) {
479 0 : if (shadowZone()->needsIncrementalBarrier())
480 0 : js::LazyScript::writeBarrierPre(lazyScript());
481 0 : JSScript* script = existingScriptNonDelazifying();
482 0 : flags_ &= ~INTERPRETED_LAZY;
483 0 : flags_ |= INTERPRETED;
484 0 : initScript(script);
485 : }
486 0 : return nonLazyScript();
487 : }
488 :
489 : // The state of a JSFunction whose script errored out during bytecode
490 : // compilation. Such JSFunctions are only reachable via GC iteration and
491 : // not from script.
492 718722 : bool hasUncompiledScript() const {
493 718722 : MOZ_ASSERT(hasScript());
494 718721 : return !u.i.s.script_;
495 : }
496 :
497 699102 : JSScript* nonLazyScript() const {
498 699102 : MOZ_ASSERT(!hasUncompiledScript());
499 699101 : return u.i.s.script_;
500 : }
501 :
502 : static bool getLength(JSContext* cx, js::HandleFunction fun, uint16_t* length);
503 :
504 25485 : js::LazyScript* lazyScript() const {
505 25485 : MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
506 25485 : return u.i.s.lazy_;
507 : }
508 :
509 9869 : js::LazyScript* lazyScriptOrNull() const {
510 9869 : MOZ_ASSERT(isInterpretedLazy());
511 9869 : return u.i.s.lazy_;
512 : }
513 :
514 107002 : js::GeneratorKind generatorKind() const {
515 107002 : if (!isInterpreted())
516 1516 : return js::NotGenerator;
517 105486 : if (hasScript())
518 103191 : return nonLazyScript()->generatorKind();
519 2295 : if (js::LazyScript* lazy = lazyScriptOrNull())
520 2295 : return lazy->generatorKind();
521 0 : MOZ_ASSERT(isSelfHostedBuiltin());
522 0 : return js::NotGenerator;
523 : }
524 :
525 39230 : bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
526 :
527 67512 : bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
528 :
529 260 : js::FunctionAsyncKind asyncKind() const {
530 260 : return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind();
531 : }
532 :
533 66317 : bool isAsync() const {
534 66317 : if (isInterpretedLazy())
535 1680 : return lazyScript()->isAsync();
536 64637 : if (hasScript())
537 63121 : return nonLazyScript()->isAsync();
538 1516 : return false;
539 : }
540 :
541 3998 : void setScript(JSScript* script_) {
542 3998 : mutableScript() = script_;
543 3998 : }
544 :
545 58158 : void initScript(JSScript* script_) {
546 58158 : mutableScript().init(script_);
547 58158 : }
548 :
549 2249 : void setUnlazifiedScript(JSScript* script) {
550 2249 : MOZ_ASSERT(isInterpretedLazy());
551 2249 : if (lazyScriptOrNull()) {
552 : // Trigger a pre barrier on the lazy script being overwritten.
553 1693 : js::LazyScript::writeBarrierPre(lazyScriptOrNull());
554 1693 : if (!lazyScript()->maybeScript())
555 1412 : lazyScript()->initScript(script);
556 : }
557 2249 : flags_ &= ~INTERPRETED_LAZY;
558 2249 : flags_ |= INTERPRETED;
559 2249 : initScript(script);
560 2249 : }
561 :
562 24481 : void initLazyScript(js::LazyScript* lazy) {
563 24481 : MOZ_ASSERT(isInterpreted());
564 24481 : flags_ &= ~INTERPRETED;
565 24481 : flags_ |= INTERPRETED_LAZY;
566 24481 : u.i.s.lazy_ = lazy;
567 24481 : }
568 :
569 34815 : JSNative native() const {
570 34815 : MOZ_ASSERT(isNative());
571 34815 : return u.n.native;
572 : }
573 :
574 6035 : JSNative maybeNative() const {
575 6035 : return isInterpreted() ? nullptr : native();
576 : }
577 :
578 48403 : void initNative(js::Native native, const JSJitInfo* jitinfo) {
579 48403 : MOZ_ASSERT(native);
580 48403 : u.n.native = native;
581 48403 : u.n.jitinfo = jitinfo;
582 48403 : }
583 :
584 25561 : const JSJitInfo* jitInfo() const {
585 25561 : MOZ_ASSERT(isNative());
586 25561 : return u.n.jitinfo;
587 : }
588 :
589 16222 : void setJitInfo(const JSJitInfo* data) {
590 16222 : MOZ_ASSERT(isNative());
591 16222 : u.n.jitinfo = data;
592 16222 : }
593 :
594 : bool isDerivedClassConstructor();
595 :
596 181 : static unsigned offsetOfNativeOrScript() {
597 : static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
598 : "native and script pointers must be in the same spot "
599 : "for offsetOfNativeOrScript() have any sense");
600 : static_assert(offsetof(U, n.native) == offsetof(U, nativeOrScript),
601 : "U::nativeOrScript must be at the same offset as "
602 : "native");
603 :
604 181 : return offsetof(JSFunction, u.nativeOrScript);
605 : }
606 :
607 2 : static unsigned offsetOfJitInfo() {
608 2 : return offsetof(JSFunction, u.n.jitinfo);
609 : }
610 :
611 : inline void trace(JSTracer* trc);
612 :
613 : /* Bound function accessors. */
614 :
615 : JSObject* getBoundFunctionTarget() const;
616 : const js::Value& getBoundFunctionThis() const;
617 : const js::Value& getBoundFunctionArgument(unsigned which) const;
618 : size_t getBoundFunctionArgumentCount() const;
619 :
620 : /*
621 : * Used to mark bound functions as such and make them constructible if the
622 : * target is. Also assigns the prototype and sets the name and correct length.
623 : */
624 : static bool finishBoundFunctionInit(JSContext* cx, js::HandleFunction bound,
625 : js::HandleObject targetObj, int32_t argCount);
626 :
627 : private:
628 62155 : js::GCPtrScript& mutableScript() {
629 62155 : MOZ_ASSERT(hasScript());
630 62155 : return *(js::GCPtrScript*)&u.i.s.script_;
631 : }
632 :
633 : inline js::FunctionExtended* toExtended();
634 : inline const js::FunctionExtended* toExtended() const;
635 :
636 : public:
637 420930 : inline bool isExtended() const {
638 420930 : bool extended = !!(flags() & EXTENDED);
639 420930 : MOZ_ASSERT_IF(isTenured(),
640 : extended == (asTenured().getAllocKind() == js::gc::AllocKind::FUNCTION_EXTENDED));
641 420928 : return extended;
642 : }
643 :
644 : /*
645 : * Accessors for data stored in extended functions. Use setExtendedSlot if
646 : * the function has already been initialized. Otherwise use
647 : * initExtendedSlot.
648 : */
649 : inline void initializeExtended();
650 : inline void initExtendedSlot(size_t which, const js::Value& val);
651 : inline void setExtendedSlot(size_t which, const js::Value& val);
652 : inline const js::Value& getExtendedSlot(size_t which) const;
653 :
654 : /* Constructs a new type for the function if necessary. */
655 : static bool setTypeForScriptedFunction(JSContext* cx, js::HandleFunction fun,
656 : bool singleton = false);
657 :
658 : /* GC support. */
659 23845 : js::gc::AllocKind getAllocKind() const {
660 : static_assert(js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
661 : "extended/non-extended AllocKinds have to be different "
662 : "for getAllocKind() to have a reason to exist");
663 :
664 23845 : js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
665 23845 : if (isExtended())
666 11543 : kind = js::gc::AllocKind::FUNCTION_EXTENDED;
667 23845 : MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
668 23845 : return kind;
669 : }
670 : };
671 :
672 : static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
673 : "shadow interface must match actual interface");
674 :
675 : extern JSString*
676 : fun_toStringHelper(JSContext* cx, js::HandleObject obj, unsigned indent);
677 :
678 : namespace js {
679 :
680 : extern bool
681 : Function(JSContext* cx, unsigned argc, Value* vp);
682 :
683 : extern bool
684 : Generator(JSContext* cx, unsigned argc, Value* vp);
685 :
686 : extern bool
687 : AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
688 :
689 : extern bool
690 : AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
691 :
692 : // Allocate a new function backed by a JSNative. Note that by default this
693 : // creates a singleton object.
694 : extern JSFunction*
695 : NewNativeFunction(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
696 : gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
697 : NewObjectKind newKind = SingletonObject);
698 :
699 : // Allocate a new constructor backed by a JSNative. Note that by default this
700 : // creates a singleton object.
701 : extern JSFunction*
702 : NewNativeConstructor(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
703 : gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
704 : NewObjectKind newKind = SingletonObject,
705 : JSFunction::Flags flags = JSFunction::NATIVE_CTOR);
706 :
707 : // Allocate a new scripted function. If enclosingEnv is null, the
708 : // global will be used. In all cases the parent of the resulting object will be
709 : // the global.
710 : extern JSFunction*
711 : NewScriptedFunction(JSContext* cx, unsigned nargs, JSFunction::Flags flags,
712 : HandleAtom atom, HandleObject proto = nullptr,
713 : gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
714 : NewObjectKind newKind = GenericObject,
715 : HandleObject enclosingEnv = nullptr);
716 :
717 : // By default, if proto is nullptr, Function.prototype is used instead.i
718 : // If protoHandling is NewFunctionExactProto, and proto is nullptr, the created
719 : // function will use nullptr as its [[Prototype]] instead. If
720 : // enclosingEnv is null, the function will have a null environment()
721 : // (yes, null, not the global). In all cases, the global will be used as the
722 : // parent.
723 :
724 : enum NewFunctionProtoHandling {
725 : NewFunctionClassProto,
726 : NewFunctionGivenProto
727 : };
728 : extern JSFunction*
729 : NewFunctionWithProto(JSContext* cx, JSNative native, unsigned nargs,
730 : JSFunction::Flags flags, HandleObject enclosingEnv, HandleAtom atom,
731 : HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
732 : NewObjectKind newKind = GenericObject,
733 : NewFunctionProtoHandling protoHandling = NewFunctionClassProto);
734 :
735 : extern JSAtom*
736 : IdToFunctionName(JSContext* cx, HandleId id,
737 : FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
738 :
739 : extern JSAtom*
740 : NameToFunctionName(JSContext* cx, HandleAtom name,
741 : FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
742 :
743 : extern bool
744 : SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
745 : FunctionPrefixKind prefixKind);
746 :
747 : extern JSFunction*
748 : DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
749 : unsigned nargs, unsigned flags,
750 : gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
751 :
752 : bool
753 : FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
754 :
755 : extern bool
756 : fun_toString(JSContext* cx, unsigned argc, Value* vp);
757 :
758 : struct WellKnownSymbols;
759 :
760 : extern bool
761 : FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols);
762 :
763 : extern bool
764 : fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp);
765 :
766 : /*
767 : * Function extended with reserved slots for use by various kinds of functions.
768 : * Most functions do not have these extensions, but enough do that efficient
769 : * storage is required (no malloc'ed reserved slots).
770 : */
771 : class FunctionExtended : public JSFunction
772 : {
773 : public:
774 : static const unsigned NUM_EXTENDED_SLOTS = 2;
775 :
776 : /* Arrow functions store their lexical new.target in the first extended slot. */
777 : static const unsigned ARROW_NEWTARGET_SLOT = 0;
778 :
779 : static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
780 :
781 : /*
782 : * Exported asm.js/wasm functions store their WasmInstanceObject in the
783 : * first slot.
784 : */
785 : static const unsigned WASM_INSTANCE_SLOT = 0;
786 :
787 : /*
788 : * wasm/asm.js exported functions store the function index of the exported
789 : * function in the original module.
790 : */
791 : static const unsigned WASM_FUNC_INDEX_SLOT = 1;
792 :
793 : /*
794 : * asm.js module functions store their WasmModuleObject in the first slot.
795 : */
796 : static const unsigned ASMJS_MODULE_SLOT = 0;
797 :
798 :
799 7 : static inline size_t offsetOfExtendedSlot(unsigned which) {
800 7 : MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
801 7 : return offsetof(FunctionExtended, extendedSlots) + which * sizeof(GCPtrValue);
802 : }
803 7 : static inline size_t offsetOfArrowNewTargetSlot() {
804 7 : return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
805 : }
806 0 : static inline size_t offsetOfMethodHomeObjectSlot() {
807 0 : return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT);
808 : }
809 :
810 : private:
811 : friend class JSFunction;
812 :
813 : /* Reserved slots available for storage by particular native functions. */
814 : GCPtrValue extendedSlots[NUM_EXTENDED_SLOTS];
815 : };
816 :
817 : extern bool
818 : CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent);
819 :
820 : extern JSFunction*
821 : CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
822 : gc::AllocKind kind = gc::AllocKind::FUNCTION,
823 : NewObjectKind newKindArg = GenericObject,
824 : HandleObject proto = nullptr);
825 :
826 : // Functions whose scripts are cloned are always given singleton types.
827 : extern JSFunction*
828 : CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
829 : HandleScope newScope,
830 : gc::AllocKind kind = gc::AllocKind::FUNCTION,
831 : HandleObject proto = nullptr);
832 :
833 : } // namespace js
834 :
835 : inline js::FunctionExtended*
836 237674 : JSFunction::toExtended()
837 : {
838 237674 : MOZ_ASSERT(isExtended());
839 237674 : return static_cast<js::FunctionExtended*>(this);
840 : }
841 :
842 : inline const js::FunctionExtended*
843 80564 : JSFunction::toExtended() const
844 : {
845 80564 : MOZ_ASSERT(isExtended());
846 80564 : return static_cast<const js::FunctionExtended*>(this);
847 : }
848 :
849 : inline void
850 42135 : JSFunction::initializeExtended()
851 : {
852 42135 : MOZ_ASSERT(isExtended());
853 :
854 42135 : MOZ_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
855 42135 : toExtended()->extendedSlots[0].init(js::UndefinedValue());
856 42135 : toExtended()->extendedSlots[1].init(js::UndefinedValue());
857 42135 : }
858 :
859 : inline void
860 15144 : JSFunction::initExtendedSlot(size_t which, const js::Value& val)
861 : {
862 15144 : MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
863 15144 : js::CheckEdgeIsNotBlackToGray(this, val);
864 15144 : MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
865 15144 : toExtended()->extendedSlots[which].init(val);
866 15144 : }
867 :
868 : inline void
869 33691 : JSFunction::setExtendedSlot(size_t which, const js::Value& val)
870 : {
871 33691 : MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
872 33691 : js::CheckEdgeIsNotBlackToGray(this, val);
873 33691 : MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
874 33691 : toExtended()->extendedSlots[which] = val;
875 33691 : }
876 :
877 : inline const js::Value&
878 40282 : JSFunction::getExtendedSlot(size_t which) const
879 : {
880 40282 : MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
881 40282 : return toExtended()->extendedSlots[which];
882 : }
883 :
884 : namespace js {
885 :
886 : JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
887 :
888 : template<XDRMode mode>
889 : bool
890 : XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
891 : HandleScriptSource sourceObject, MutableHandleFunction objp);
892 :
893 : /*
894 : * Report an error that call.thisv is not compatible with the specified class,
895 : * assuming that the method (clasp->name).prototype.<name of callee function>
896 : * is what was called.
897 : */
898 : extern void
899 : ReportIncompatibleMethod(JSContext* cx, const CallArgs& args, const Class* clasp);
900 :
901 : /*
902 : * Report an error that call.thisv is not an acceptable this for the callee
903 : * function.
904 : */
905 : extern void
906 : ReportIncompatible(JSContext* cx, const CallArgs& args);
907 :
908 : extern const JSFunctionSpec function_methods[];
909 : extern const JSFunctionSpec function_selfhosted_methods[];
910 :
911 : extern bool
912 : fun_apply(JSContext* cx, unsigned argc, Value* vp);
913 :
914 : extern bool
915 : fun_call(JSContext* cx, unsigned argc, Value* vp);
916 :
917 : } /* namespace js */
918 :
919 : #ifdef DEBUG
920 : namespace JS {
921 : namespace detail {
922 :
923 : JS_PUBLIC_API(void)
924 : CheckIsValidConstructible(const Value& calleev);
925 :
926 : } // namespace detail
927 : } // namespace JS
928 : #endif
929 :
930 : #endif /* jsfun_h */
|