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 namespace frontend {
21 class FunctionBox;
22 }
23
24 class FunctionExtended;
25
26 typedef JSNative Native;
27 } // namespace js
28
29 struct JSAtomState;
30
31 class JSFunction : public js::NativeObject
32 {
33 public:
34 static const js::Class class_;
35
36 enum FunctionKind {
37 NormalFunction = 0,
38 Arrow, /* ES6 '(args) => body' syntax */
39 Method, /* ES6 MethodDefinition */
40 ClassConstructor,
41 Getter,
42 Setter,
43 AsmJS, /* function is an asm.js module or exported function */
44 FunctionKindLimit
45 };
46
47 enum Flags {
48 INTERPRETED = 0x0001, /* function has a JSScript and environment. */
49 CONSTRUCTOR = 0x0002, /* function that can be called as a constructor */
50 EXTENDED = 0x0004, /* structure is FunctionExtended */
51 IS_FUN_PROTO = 0x0008, /* function is Function.prototype for some global object */
52 EXPR_BODY = 0x0010, /* arrow function with expression body or
53 * expression closure: function(x) x*x */
54 HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a
55 name was guessed for it anyway */
56 LAMBDA = 0x0040, /* function comes from a FunctionExpression, ArrowFunction, or
57 Function() call (not a FunctionDeclaration or nonstandard
58 function-statement) */
59 SELF_HOSTED = 0x0080, /* function is self-hosted builtin and must not be
60 decompilable nor constructible. */
61 HAS_REST = 0x0100, /* function has a rest (...) parameter */
62 INTERPRETED_LAZY = 0x0200, /* function is interpreted but doesn't have a script yet */
63 RESOLVED_LENGTH = 0x0400, /* f.length has been resolved (see fun_resolve). */
64 RESOLVED_NAME = 0x0800, /* f.name has been resolved (see fun_resolve). */
65 BEING_PARSED = 0x1000, /* function is currently being parsed; has
66 a funbox in place of an environment */
67
68 FUNCTION_KIND_SHIFT = 13,
69 FUNCTION_KIND_MASK = 0x7 << FUNCTION_KIND_SHIFT,
70
71 ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
72 ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
73 METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
74 CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
75 GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
76 SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
77
78 /* Derived Flags values for convenience: */
79 NATIVE_FUN = 0,
80 NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
81 NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
82 ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
83 ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
84 INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
85 INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND,
86 INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
87 INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
88 INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
89 INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
90 INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
91 INTERPRETED_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
92 INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
93 INTERPRETED_GENERATOR = INTERPRETED,
94 NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
95
96 STABLE_ACROSS_CLONES = IS_FUN_PROTO | CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM |
97 LAMBDA | SELF_HOSTED | HAS_REST | FUNCTION_KIND_MASK
98 };
99
100 static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
101 "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
102 static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
103 "FunctionKind doesn't fit into flags_");
104
105 // Implemented in Parser.cpp. Used so the static scope chain may be walked
106 // in Parser without a JSScript.
107 class MOZ_STACK_CLASS AutoParseUsingFunctionBox
108 {
109 js::RootedFunction fun_;
110 js::RootedObject oldEnv_;
111
112 public:
113 AutoParseUsingFunctionBox(js::ExclusiveContext* cx, js::frontend::FunctionBox* funbox);
114 ~AutoParseUsingFunctionBox();
115 };
116
117 private:
118 uint16_t nargs_; /* number of formal arguments
119 (including defaults and the rest parameter unlike f.length) */
120 uint16_t flags_; /* bitfield composed of the above Flags enum, as well as the kind */
121 union U {
122 class Native {
123 friend class JSFunction;
124 js::Native native; /* native method pointer or null */
125 const JSJitInfo* jitinfo; /* Information about this function to be
126 used by the JIT;
127 use the accessor! */
128 } n;
129 struct Scripted {
130 union {
131 JSScript* script_; /* interpreted bytecode descriptor or null;
132 use the accessor! */
133 js::LazyScript* lazy_; /* lazily compiled script, or nullptr */
134 } s;
135 union {
136 JSObject* env_; /* environment for new activations;
137 use the accessor! */
138 js::frontend::FunctionBox* funbox_; /* the function box when parsing */
139 };
140 } i;
141 void* nativeOrScript;
142 } u;
143 js::HeapPtrAtom atom_; /* name for diagnostics and decompiling */
144
145 public:
146
147 /* Call objects must be created for each invocation of this function. */
needsCallObject()148 bool needsCallObject() const {
149 MOZ_ASSERT(!isInterpretedLazy());
150 MOZ_ASSERT(!isBeingParsed());
151
152 if (isNative())
153 return false;
154
155 // Note: this should be kept in sync with FunctionBox::needsCallObject().
156 return nonLazyScript()->hasAnyAliasedBindings() ||
157 nonLazyScript()->funHasExtensibleScope() ||
158 nonLazyScript()->funNeedsDeclEnvObject() ||
159 nonLazyScript()->needsHomeObject() ||
160 nonLazyScript()->isDerivedClassConstructor() ||
161 isGenerator();
162 }
163
nargs()164 size_t nargs() const {
165 return nargs_;
166 }
167
flags()168 uint16_t flags() const {
169 return flags_;
170 }
171
kind()172 FunctionKind kind() const {
173 return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> FUNCTION_KIND_SHIFT);
174 }
175
176 /* A function can be classified as either native (C++) or interpreted (JS): */
isInterpreted()177 bool isInterpreted() const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
isNative()178 bool isNative() const { return !isInterpreted(); }
179
isConstructor()180 bool isConstructor() const { return flags() & CONSTRUCTOR; }
181
182 /* Possible attributes of a native function: */
isAsmJSNative()183 bool isAsmJSNative() const { return kind() == AsmJS; }
184
185 /* Possible attributes of an interpreted function: */
isFunctionPrototype()186 bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
isExprBody()187 bool isExprBody() const { return flags() & EXPR_BODY; }
hasGuessedAtom()188 bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
isLambda()189 bool isLambda() const { return flags() & LAMBDA; }
isSelfHostedBuiltin()190 bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; }
hasRest()191 bool hasRest() const { return flags() & HAS_REST; }
isInterpretedLazy()192 bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
hasScript()193 bool hasScript() const { return flags() & INTERPRETED; }
isBeingParsed()194 bool isBeingParsed() const { return flags() & BEING_PARSED; }
195
196 // Arrow functions store their lexical new.target in the first extended slot.
isArrow()197 bool isArrow() const { return kind() == Arrow; }
198 // Every class-constructor is also a method.
isMethod()199 bool isMethod() const { return kind() == Method || kind() == ClassConstructor; }
isClassConstructor()200 bool isClassConstructor() const { return kind() == ClassConstructor; }
201
isGetter()202 bool isGetter() const { return kind() == Getter; }
isSetter()203 bool isSetter() const { return kind() == Setter; }
204
allowSuperProperty()205 bool allowSuperProperty() const {
206 return isMethod() || isGetter() || isSetter();
207 }
208
hasResolvedLength()209 bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; }
hasResolvedName()210 bool hasResolvedName() const { return flags() & RESOLVED_NAME; }
211
hasJITCode()212 bool hasJITCode() const {
213 if (!hasScript())
214 return false;
215
216 return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
217 }
218
219 /* Compound attributes: */
isBuiltin()220 bool isBuiltin() const {
221 return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
222 }
223
isNamedLambda()224 bool isNamedLambda() const {
225 return isLambda() && displayAtom() && !hasGuessedAtom();
226 }
227
hasLexicalThis()228 bool hasLexicalThis() const {
229 return isArrow() || nonLazyScript()->isGeneratorExp();
230 }
231
232 bool isBuiltinFunctionConstructor();
233
234 /* Returns the strictness of this function, which must be interpreted. */
strict()235 bool strict() const {
236 MOZ_ASSERT(isInterpreted());
237 return isInterpretedLazy() ? lazyScript()->strict() : nonLazyScript()->strict();
238 }
239
setFlags(uint16_t flags)240 void setFlags(uint16_t flags) {
241 this->flags_ = flags;
242 }
setKind(FunctionKind kind)243 void setKind(FunctionKind kind) {
244 this->flags_ &= ~FUNCTION_KIND_MASK;
245 this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
246 }
247
248 // Make the function constructible.
setIsConstructor()249 void setIsConstructor() {
250 MOZ_ASSERT(!isConstructor());
251 MOZ_ASSERT(isSelfHostedBuiltin());
252 flags_ |= CONSTRUCTOR;
253 }
254
255 // Can be called multiple times by the parser.
setArgCount(uint16_t nargs)256 void setArgCount(uint16_t nargs) {
257 this->nargs_ = nargs;
258 }
259
260 // Can be called multiple times by the parser.
setHasRest()261 void setHasRest() {
262 flags_ |= HAS_REST;
263 }
264
setIsSelfHostedBuiltin()265 void setIsSelfHostedBuiltin() {
266 MOZ_ASSERT(!isSelfHostedBuiltin());
267 flags_ |= SELF_HOSTED;
268 // Self-hosted functions should not be constructable.
269 flags_ &= ~CONSTRUCTOR;
270 }
271
setIsFunctionPrototype()272 void setIsFunctionPrototype() {
273 MOZ_ASSERT(!isFunctionPrototype());
274 flags_ |= IS_FUN_PROTO;
275 }
276
277 // Can be called multiple times by the parser.
setIsExprBody()278 void setIsExprBody() {
279 flags_ |= EXPR_BODY;
280 }
281
setArrow()282 void setArrow() {
283 setKind(Arrow);
284 }
285
setResolvedLength()286 void setResolvedLength() {
287 flags_ |= RESOLVED_LENGTH;
288 }
289
setResolvedName()290 void setResolvedName() {
291 flags_ |= RESOLVED_NAME;
292 }
293
atom()294 JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
295
name()296 js::PropertyName* name() const {
297 return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName();
298 }
299
initAtom(JSAtom * atom)300 void initAtom(JSAtom* atom) { atom_.init(atom); }
301
displayAtom()302 JSAtom* displayAtom() const {
303 return atom_;
304 }
305
setGuessedAtom(JSAtom * atom)306 void setGuessedAtom(JSAtom* atom) {
307 MOZ_ASSERT(!atom_);
308 MOZ_ASSERT(atom);
309 MOZ_ASSERT(!hasGuessedAtom());
310 atom_ = atom;
311 flags_ |= HAS_GUESSED_ATOM;
312 }
313
314 /* uint16_t representation bounds number of call object dynamic slots. */
315 enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
316
317 /*
318 * For an interpreted function, accessors for the initial scope object of
319 * activations (stack frames) of the function.
320 */
environment()321 JSObject* environment() const {
322 MOZ_ASSERT(isInterpreted() && !isBeingParsed());
323 return u.i.env_;
324 }
325
setEnvironment(JSObject * obj)326 void setEnvironment(JSObject* obj) {
327 MOZ_ASSERT(isInterpreted() && !isBeingParsed());
328 *reinterpret_cast<js::HeapPtrObject*>(&u.i.env_) = obj;
329 }
330
initEnvironment(JSObject * obj)331 void initEnvironment(JSObject* obj) {
332 MOZ_ASSERT(isInterpreted() && !isBeingParsed());
333 reinterpret_cast<js::HeapPtrObject*>(&u.i.env_)->init(obj);
334 }
335
unsetEnvironment()336 void unsetEnvironment() {
337 setEnvironment(nullptr);
338 }
339
340 private:
setFunctionBox(js::frontend::FunctionBox * funbox)341 void setFunctionBox(js::frontend::FunctionBox* funbox) {
342 MOZ_ASSERT(isInterpreted());
343 MOZ_ASSERT_IF(!isBeingParsed(), !environment());
344 flags_ |= BEING_PARSED;
345 u.i.funbox_ = funbox;
346 }
347
unsetFunctionBox()348 void unsetFunctionBox() {
349 MOZ_ASSERT(isBeingParsed());
350 flags_ &= ~BEING_PARSED;
351 u.i.funbox_ = nullptr;
352 }
353
354 public:
offsetOfNargs()355 static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
offsetOfFlags()356 static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
offsetOfEnvironment()357 static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
offsetOfAtom()358 static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
359
360 static bool createScriptForLazilyInterpretedFunction(JSContext* cx, js::HandleFunction fun);
361 void maybeRelazify(JSRuntime* rt);
362
363 // Function Scripts
364 //
365 // Interpreted functions may either have an explicit JSScript (hasScript())
366 // or be lazy with sufficient information to construct the JSScript if
367 // necessary (isInterpretedLazy()).
368 //
369 // A lazy function will have a LazyScript if the function came from parsed
370 // source, or nullptr if the function is a clone of a self hosted function.
371 //
372 // There are several methods to get the script of an interpreted function:
373 //
374 // - For all interpreted functions, getOrCreateScript() will get the
375 // JSScript, delazifying the function if necessary. This is the safest to
376 // use, but has extra checks, requires a cx and may trigger a GC.
377 //
378 // - For inlined functions which may have a LazyScript but whose JSScript
379 // is known to exist, existingScriptForInlinedFunction() will get the
380 // script and delazify the function if necessary.
381 //
382 // - For functions known to have a JSScript, nonLazyScript() will get it.
383
getOrCreateScript(JSContext * cx)384 JSScript* getOrCreateScript(JSContext* cx) {
385 MOZ_ASSERT(isInterpreted());
386 MOZ_ASSERT(cx);
387 if (isInterpretedLazy()) {
388 JS::RootedFunction self(cx, this);
389 if (!createScriptForLazilyInterpretedFunction(cx, self))
390 return nullptr;
391 return self->nonLazyScript();
392 }
393 return nonLazyScript();
394 }
395
existingScriptForInlinedFunction()396 JSScript* existingScriptForInlinedFunction() {
397 MOZ_ASSERT(isInterpreted());
398 if (isInterpretedLazy()) {
399 // Get the script from the canonical function. Ion used the
400 // canonical function to inline the script and because it has
401 // Baseline code it has not been relazified. Note that we can't
402 // use lazyScript->script_ here as it may be null in some cases,
403 // see bug 976536.
404 js::LazyScript* lazy = lazyScript();
405 JSFunction* fun = lazy->functionNonDelazifying();
406 MOZ_ASSERT(fun);
407 JSScript* script = fun->nonLazyScript();
408
409 if (shadowZone()->needsIncrementalBarrier())
410 js::LazyScript::writeBarrierPre(lazy);
411
412 flags_ &= ~INTERPRETED_LAZY;
413 flags_ |= INTERPRETED;
414 initScript(script);
415 }
416 return nonLazyScript();
417 }
418
419 // The state of a JSFunction whose script errored out during bytecode
420 // compilation. Such JSFunctions are only reachable via GC iteration and
421 // not from script.
hasUncompiledScript()422 bool hasUncompiledScript() const {
423 MOZ_ASSERT(hasScript());
424 return !u.i.s.script_;
425 }
426
nonLazyScript()427 JSScript* nonLazyScript() const {
428 MOZ_ASSERT(!hasUncompiledScript());
429 return u.i.s.script_;
430 }
431
getLength(JSContext * cx,uint16_t * length)432 bool getLength(JSContext* cx, uint16_t* length) {
433 JS::RootedFunction self(cx, this);
434 if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
435 return false;
436
437 *length = self->hasScript() ? self->nonLazyScript()->funLength()
438 : (self->nargs() - self->hasRest());
439 return true;
440 }
441
lazyScript()442 js::LazyScript* lazyScript() const {
443 MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
444 return u.i.s.lazy_;
445 }
446
lazyScriptOrNull()447 js::LazyScript* lazyScriptOrNull() const {
448 MOZ_ASSERT(isInterpretedLazy());
449 return u.i.s.lazy_;
450 }
451
functionBox()452 js::frontend::FunctionBox* functionBox() const {
453 MOZ_ASSERT(isBeingParsed());
454 return u.i.funbox_;
455 }
456
generatorKind()457 js::GeneratorKind generatorKind() const {
458 if (!isInterpreted())
459 return js::NotGenerator;
460 if (hasScript())
461 return nonLazyScript()->generatorKind();
462 if (js::LazyScript* lazy = lazyScriptOrNull())
463 return lazy->generatorKind();
464 MOZ_ASSERT(isSelfHostedBuiltin());
465 return js::NotGenerator;
466 }
467
isGenerator()468 bool isGenerator() const { return generatorKind() != js::NotGenerator; }
469
isLegacyGenerator()470 bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
471
isStarGenerator()472 bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
473
setScript(JSScript * script_)474 void setScript(JSScript* script_) {
475 mutableScript() = script_;
476 }
477
initScript(JSScript * script_)478 void initScript(JSScript* script_) {
479 mutableScript().init(script_);
480 }
481
setUnlazifiedScript(JSScript * script)482 void setUnlazifiedScript(JSScript* script) {
483 // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
484 // lazy script before it is overwritten here.
485 MOZ_ASSERT(isInterpretedLazy());
486 if (lazyScriptOrNull() && !lazyScript()->maybeScript())
487 lazyScript()->initScript(script);
488 flags_ &= ~INTERPRETED_LAZY;
489 flags_ |= INTERPRETED;
490 initScript(script);
491 }
492
initLazyScript(js::LazyScript * lazy)493 void initLazyScript(js::LazyScript* lazy) {
494 MOZ_ASSERT(isInterpreted());
495 flags_ &= ~INTERPRETED;
496 flags_ |= INTERPRETED_LAZY;
497 u.i.s.lazy_ = lazy;
498 }
499
native()500 JSNative native() const {
501 MOZ_ASSERT(isNative());
502 return u.n.native;
503 }
504
maybeNative()505 JSNative maybeNative() const {
506 return isInterpreted() ? nullptr : native();
507 }
508
initNative(js::Native native,const JSJitInfo * jitinfo)509 void initNative(js::Native native, const JSJitInfo* jitinfo) {
510 MOZ_ASSERT(native);
511 u.n.native = native;
512 u.n.jitinfo = jitinfo;
513 }
514
jitInfo()515 const JSJitInfo* jitInfo() const {
516 MOZ_ASSERT(isNative());
517 return u.n.jitinfo;
518 }
519
setJitInfo(const JSJitInfo * data)520 void setJitInfo(const JSJitInfo* data) {
521 MOZ_ASSERT(isNative());
522 u.n.jitinfo = data;
523 }
524
isDerivedClassConstructor()525 bool isDerivedClassConstructor() {
526 bool derived;
527 if (isInterpretedLazy())
528 derived = !isSelfHostedBuiltin() && lazyScript()->isDerivedClassConstructor();
529 else
530 derived = nonLazyScript()->isDerivedClassConstructor();
531 MOZ_ASSERT_IF(derived, isClassConstructor());
532 return derived;
533 }
534
offsetOfNativeOrScript()535 static unsigned offsetOfNativeOrScript() {
536 static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
537 "native and script pointers must be in the same spot "
538 "for offsetOfNativeOrScript() have any sense");
539 static_assert(offsetof(U, n.native) == offsetof(U, nativeOrScript),
540 "U::nativeOrScript must be at the same offset as "
541 "native");
542
543 return offsetof(JSFunction, u.nativeOrScript);
544 }
545
546 inline void trace(JSTracer* trc);
547
548 /* Bound function accessors. */
549
550 inline bool initBoundFunction(JSContext* cx, js::HandleObject target, js::HandleValue thisArg,
551 const js::Value* args, unsigned argslen);
552
553 JSObject* getBoundFunctionTarget() const;
554 const js::Value& getBoundFunctionThis() const;
555 const js::Value& getBoundFunctionArgument(unsigned which) const;
556 size_t getBoundFunctionArgumentCount() const;
557
558 private:
mutableScript()559 js::HeapPtrScript& mutableScript() {
560 MOZ_ASSERT(hasScript());
561 return *(js::HeapPtrScript*)&u.i.s.script_;
562 }
563
564 inline js::FunctionExtended* toExtended();
565 inline const js::FunctionExtended* toExtended() const;
566
567 public:
isExtended()568 inline bool isExtended() const {
569 bool extended = !!(flags() & EXTENDED);
570 MOZ_ASSERT_IF(isTenured(),
571 extended == (asTenured().getAllocKind() == js::gc::AllocKind::FUNCTION_EXTENDED));
572 return extended;
573 }
574
575 /*
576 * Accessors for data stored in extended functions. Use setExtendedSlot if
577 * the function has already been initialized. Otherwise use
578 * initExtendedSlot.
579 */
580 inline void initializeExtended();
581 inline void initExtendedSlot(size_t which, const js::Value& val);
582 inline void setExtendedSlot(size_t which, const js::Value& val);
583 inline const js::Value& getExtendedSlot(size_t which) const;
584
585 /* Constructs a new type for the function if necessary. */
586 static bool setTypeForScriptedFunction(js::ExclusiveContext* cx, js::HandleFunction fun,
587 bool singleton = false);
588
589 /* GC support. */
getAllocKind()590 js::gc::AllocKind getAllocKind() const {
591 static_assert(js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
592 "extended/non-extended AllocKinds have to be different "
593 "for getAllocKind() to have a reason to exist");
594
595 js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
596 if (isExtended())
597 kind = js::gc::AllocKind::FUNCTION_EXTENDED;
598 MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
599 return kind;
600 }
601 };
602
603 static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
604 "shadow interface must match actual interface");
605
606 extern JSString*
607 fun_toStringHelper(JSContext* cx, js::HandleObject obj, unsigned indent);
608
609 namespace js {
610
611 extern bool
612 Function(JSContext* cx, unsigned argc, Value* vp);
613
614 extern bool
615 Generator(JSContext* cx, unsigned argc, Value* vp);
616
617 // Allocate a new function backed by a JSNative.
618 extern JSFunction*
619 NewNativeFunction(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
620 gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
621 NewObjectKind newKind = GenericObject);
622
623 // Allocate a new constructor backed by a JSNative.
624 extern JSFunction*
625 NewNativeConstructor(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
626 gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
627 NewObjectKind newKind = GenericObject,
628 JSFunction::Flags flags = JSFunction::NATIVE_CTOR);
629
630 // Allocate a new scripted function. If enclosingDynamicScope is null, the
631 // global will be used. In all cases the parent of the resulting object will be
632 // the global.
633 extern JSFunction*
634 NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags,
635 HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
636 NewObjectKind newKind = GenericObject,
637 HandleObject enclosingDynamicScope = nullptr);
638
639 // By default, if proto is nullptr, Function.prototype is used instead.i
640 // If protoHandling is NewFunctionExactProto, and proto is nullptr, the created
641 // function will use nullptr as its [[Prototype]] instead. If
642 // enclosingDynamicScope is null, the function will have a null environment()
643 // (yes, null, not the global). In all cases, the global will be used as the
644 // parent.
645
646 enum NewFunctionProtoHandling {
647 NewFunctionClassProto,
648 NewFunctionGivenProto
649 };
650 extern JSFunction*
651 NewFunctionWithProto(ExclusiveContext* cx, JSNative native, unsigned nargs,
652 JSFunction::Flags flags, HandleObject enclosingDynamicScope, HandleAtom atom,
653 HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
654 NewObjectKind newKind = GenericObject,
655 NewFunctionProtoHandling protoHandling = NewFunctionClassProto);
656
657 extern JSAtom*
658 IdToFunctionName(JSContext* cx, HandleId id);
659
660 extern JSFunction*
661 DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
662 unsigned nargs, unsigned flags,
663 gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
664
665 bool
666 FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
667
668 extern bool
669 fun_toString(JSContext* cx, unsigned argc, Value* vp);
670
671 extern bool
672 fun_bind(JSContext* cx, unsigned argc, Value* vp);
673
674 /*
675 * Function extended with reserved slots for use by various kinds of functions.
676 * Most functions do not have these extensions, but enough do that efficient
677 * storage is required (no malloc'ed reserved slots).
678 */
679 class FunctionExtended : public JSFunction
680 {
681 public:
682 static const unsigned NUM_EXTENDED_SLOTS = 2;
683
684 /* Arrow functions store their lexical new.target in the first extended slot. */
685 static const unsigned ARROW_NEWTARGET_SLOT = 0;
686
687 static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
688
offsetOfExtendedSlot(unsigned which)689 static inline size_t offsetOfExtendedSlot(unsigned which) {
690 MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
691 return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue);
692 }
offsetOfArrowNewTargetSlot()693 static inline size_t offsetOfArrowNewTargetSlot() {
694 return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
695 }
696
697 private:
698 friend class JSFunction;
699
700 /* Reserved slots available for storage by particular native functions. */
701 HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
702 };
703
704 extern bool
705 CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent);
706
707 extern JSFunction*
708 CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
709 gc::AllocKind kind = gc::AllocKind::FUNCTION,
710 NewObjectKind newKindArg = GenericObject,
711 HandleObject proto = nullptr);
712
713 // Functions whose scripts are cloned are always given singleton types.
714 extern JSFunction*
715 CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
716 HandleObject newStaticScope,
717 gc::AllocKind kind = gc::AllocKind::FUNCTION,
718 HandleObject proto = nullptr);
719
720 extern bool
721 FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
722 size_t* bodyEnd);
723
724 } // namespace js
725
726 inline js::FunctionExtended*
toExtended()727 JSFunction::toExtended()
728 {
729 MOZ_ASSERT(isExtended());
730 return static_cast<js::FunctionExtended*>(this);
731 }
732
733 inline const js::FunctionExtended*
toExtended()734 JSFunction::toExtended() const
735 {
736 MOZ_ASSERT(isExtended());
737 return static_cast<const js::FunctionExtended*>(this);
738 }
739
740 inline void
initializeExtended()741 JSFunction::initializeExtended()
742 {
743 MOZ_ASSERT(isExtended());
744
745 MOZ_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
746 toExtended()->extendedSlots[0].init(js::UndefinedValue());
747 toExtended()->extendedSlots[1].init(js::UndefinedValue());
748 }
749
750 inline void
initExtendedSlot(size_t which,const js::Value & val)751 JSFunction::initExtendedSlot(size_t which, const js::Value& val)
752 {
753 MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
754 toExtended()->extendedSlots[which].init(val);
755 }
756
757 inline void
setExtendedSlot(size_t which,const js::Value & val)758 JSFunction::setExtendedSlot(size_t which, const js::Value& val)
759 {
760 MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
761 toExtended()->extendedSlots[which] = val;
762 }
763
764 inline const js::Value&
getExtendedSlot(size_t which)765 JSFunction::getExtendedSlot(size_t which) const
766 {
767 MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
768 return toExtended()->extendedSlots[which];
769 }
770
771 namespace js {
772
773 JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
774
775 template<XDRMode mode>
776 bool
777 XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope,
778 HandleScript enclosingScript, MutableHandleFunction objp);
779
780 /*
781 * Report an error that call.thisv is not compatible with the specified class,
782 * assuming that the method (clasp->name).prototype.<name of callee function>
783 * is what was called.
784 */
785 extern void
786 ReportIncompatibleMethod(JSContext* cx, CallReceiver call, const Class* clasp);
787
788 /*
789 * Report an error that call.thisv is not an acceptable this for the callee
790 * function.
791 */
792 extern void
793 ReportIncompatible(JSContext* cx, CallReceiver call);
794
795 bool
796 CallOrConstructBoundFunction(JSContext*, unsigned, js::Value*);
797
798 extern const JSFunctionSpec function_methods[];
799
800 extern bool
801 fun_apply(JSContext* cx, unsigned argc, Value* vp);
802
803 extern bool
804 fun_call(JSContext* cx, unsigned argc, Value* vp);
805
806 } /* namespace js */
807
808 #ifdef DEBUG
809 namespace JS {
810 namespace detail {
811
812 JS_PUBLIC_API(void)
813 CheckIsValidConstructible(Value calleev);
814
815 } // namespace detail
816 } // namespace JS
817 #endif
818
819 #endif /* jsfun_h */
820