js/src/jsfun.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jsfun_h
michael@0 8 #define jsfun_h
michael@0 9
michael@0 10 /*
michael@0 11 * JS function definitions.
michael@0 12 */
michael@0 13
michael@0 14 #include "jsobj.h"
michael@0 15 #include "jsscript.h"
michael@0 16 #include "jstypes.h"
michael@0 17
michael@0 18 namespace js {
michael@0 19 class FunctionExtended;
michael@0 20
michael@0 21 typedef JSNative Native;
michael@0 22 typedef JSParallelNative ParallelNative;
michael@0 23 typedef JSThreadSafeNative ThreadSafeNative;
michael@0 24 }
michael@0 25
michael@0 26 struct JSAtomState;
michael@0 27
michael@0 28 class JSFunction : public JSObject
michael@0 29 {
michael@0 30 public:
michael@0 31 static const js::Class class_;
michael@0 32
michael@0 33 enum Flags {
michael@0 34 INTERPRETED = 0x0001, /* function has a JSScript and environment. */
michael@0 35 NATIVE_CTOR = 0x0002, /* native that can be called as a constructor */
michael@0 36 EXTENDED = 0x0004, /* structure is FunctionExtended */
michael@0 37 IS_FUN_PROTO = 0x0010, /* function is Function.prototype for some global object */
michael@0 38 EXPR_CLOSURE = 0x0020, /* expression closure: function(x) x*x */
michael@0 39 HAS_GUESSED_ATOM = 0x0040, /* function had no explicit name, but a
michael@0 40 name was guessed for it anyway */
michael@0 41 LAMBDA = 0x0080, /* function comes from a FunctionExpression, ArrowFunction, or
michael@0 42 Function() call (not a FunctionDeclaration or nonstandard
michael@0 43 function-statement) */
michael@0 44 SELF_HOSTED = 0x0100, /* function is self-hosted builtin and must not be
michael@0 45 decompilable nor constructible. */
michael@0 46 SELF_HOSTED_CTOR = 0x0200, /* function is self-hosted builtin constructor and
michael@0 47 must be constructible but not decompilable. */
michael@0 48 HAS_REST = 0x0400, /* function has a rest (...) parameter */
michael@0 49 // 0x0800 is available
michael@0 50 INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */
michael@0 51 ARROW = 0x2000, /* ES6 '(args) => body' syntax */
michael@0 52
michael@0 53 /* Derived Flags values for convenience: */
michael@0 54 NATIVE_FUN = 0,
michael@0 55 NATIVE_LAMBDA_FUN = NATIVE_FUN | LAMBDA,
michael@0 56 INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
michael@0 57 INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW
michael@0 58 };
michael@0 59
michael@0 60 static void staticAsserts() {
michael@0 61 JS_STATIC_ASSERT(INTERPRETED == JS_FUNCTION_INTERPRETED_BIT);
michael@0 62 static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
michael@0 63 "shadow interface must match actual interface");
michael@0 64 }
michael@0 65
michael@0 66 private:
michael@0 67 uint16_t nargs_; /* number of formal arguments
michael@0 68 (including defaults and the rest parameter unlike f.length) */
michael@0 69 uint16_t flags_; /* bitfield composed of the above Flags enum */
michael@0 70 union U {
michael@0 71 class Native {
michael@0 72 friend class JSFunction;
michael@0 73 js::Native native; /* native method pointer or null */
michael@0 74 const JSJitInfo *jitinfo; /* Information about this function to be
michael@0 75 used by the JIT;
michael@0 76 use the accessor! */
michael@0 77 } n;
michael@0 78 struct Scripted {
michael@0 79 union {
michael@0 80 JSScript *script_; /* interpreted bytecode descriptor or null;
michael@0 81 use the accessor! */
michael@0 82 js::LazyScript *lazy_; /* lazily compiled script, or nullptr */
michael@0 83 } s;
michael@0 84 JSObject *env_; /* environment for new activations;
michael@0 85 use the accessor! */
michael@0 86 } i;
michael@0 87 void *nativeOrScript;
michael@0 88 } u;
michael@0 89 js::HeapPtrAtom atom_; /* name for diagnostics and decompiling */
michael@0 90
michael@0 91 public:
michael@0 92
michael@0 93 /* Call objects must be created for each invocation of a heavyweight function. */
michael@0 94 bool isHeavyweight() const {
michael@0 95 JS_ASSERT(!isInterpretedLazy());
michael@0 96
michael@0 97 if (isNative())
michael@0 98 return false;
michael@0 99
michael@0 100 // Note: this should be kept in sync with FunctionBox::isHeavyweight().
michael@0 101 return nonLazyScript()->hasAnyAliasedBindings() ||
michael@0 102 nonLazyScript()->funHasExtensibleScope() ||
michael@0 103 nonLazyScript()->funNeedsDeclEnvObject() ||
michael@0 104 isGenerator();
michael@0 105 }
michael@0 106
michael@0 107 size_t nargs() const {
michael@0 108 return nargs_;
michael@0 109 }
michael@0 110
michael@0 111 uint16_t flags() const {
michael@0 112 return flags_;
michael@0 113 }
michael@0 114
michael@0 115 /* A function can be classified as either native (C++) or interpreted (JS): */
michael@0 116 bool isInterpreted() const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
michael@0 117 bool isNative() const { return !isInterpreted(); }
michael@0 118
michael@0 119 /* Possible attributes of a native function: */
michael@0 120 bool isNativeConstructor() const { return flags() & NATIVE_CTOR; }
michael@0 121
michael@0 122 /* Possible attributes of an interpreted function: */
michael@0 123 bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
michael@0 124 bool isExprClosure() const { return flags() & EXPR_CLOSURE; }
michael@0 125 bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
michael@0 126 bool isLambda() const { return flags() & LAMBDA; }
michael@0 127 bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; }
michael@0 128 bool isSelfHostedConstructor() const { return flags() & SELF_HOSTED_CTOR; }
michael@0 129 bool hasRest() const { return flags() & HAS_REST; }
michael@0 130
michael@0 131 bool isInterpretedLazy() const {
michael@0 132 return flags() & INTERPRETED_LAZY;
michael@0 133 }
michael@0 134 bool hasScript() const {
michael@0 135 return flags() & INTERPRETED;
michael@0 136 }
michael@0 137
michael@0 138 bool hasJITCode() const {
michael@0 139 if (!hasScript())
michael@0 140 return false;
michael@0 141
michael@0 142 return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
michael@0 143 }
michael@0 144
michael@0 145 // Arrow functions store their lexical |this| in the first extended slot.
michael@0 146 bool isArrow() const { return flags() & ARROW; }
michael@0 147
michael@0 148 /* Compound attributes: */
michael@0 149 bool isBuiltin() const {
michael@0 150 return isNative() || isSelfHostedBuiltin();
michael@0 151 }
michael@0 152 bool isInterpretedConstructor() const {
michael@0 153 // Note: the JITs inline this check, so be careful when making changes
michael@0 154 // here. See IonMacroAssembler::branchIfNotInterpretedConstructor.
michael@0 155 return isInterpreted() && !isFunctionPrototype() && !isArrow() &&
michael@0 156 (!isSelfHostedBuiltin() || isSelfHostedConstructor());
michael@0 157 }
michael@0 158 bool isNamedLambda() const {
michael@0 159 return isLambda() && displayAtom() && !hasGuessedAtom();
michael@0 160 }
michael@0 161 bool hasParallelNative() const {
michael@0 162 return isNative() && jitInfo() && jitInfo()->hasParallelNative();
michael@0 163 }
michael@0 164
michael@0 165 bool isBuiltinFunctionConstructor();
michael@0 166
michael@0 167 /* Returns the strictness of this function, which must be interpreted. */
michael@0 168 bool strict() const {
michael@0 169 return nonLazyScript()->strict();
michael@0 170 }
michael@0 171
michael@0 172 void setFlags(uint16_t flags) {
michael@0 173 this->flags_ = flags;
michael@0 174 }
michael@0 175
michael@0 176 // Can be called multiple times by the parser.
michael@0 177 void setArgCount(uint16_t nargs) {
michael@0 178 this->nargs_ = nargs;
michael@0 179 }
michael@0 180
michael@0 181 // Can be called multiple times by the parser.
michael@0 182 void setHasRest() {
michael@0 183 flags_ |= HAS_REST;
michael@0 184 }
michael@0 185
michael@0 186 void setIsSelfHostedBuiltin() {
michael@0 187 JS_ASSERT(!isSelfHostedBuiltin());
michael@0 188 flags_ |= SELF_HOSTED;
michael@0 189 }
michael@0 190
michael@0 191 void setIsSelfHostedConstructor() {
michael@0 192 JS_ASSERT(!isSelfHostedConstructor());
michael@0 193 flags_ |= SELF_HOSTED_CTOR;
michael@0 194 }
michael@0 195
michael@0 196 void setIsFunctionPrototype() {
michael@0 197 JS_ASSERT(!isFunctionPrototype());
michael@0 198 flags_ |= IS_FUN_PROTO;
michael@0 199 }
michael@0 200
michael@0 201 // Can be called multiple times by the parser.
michael@0 202 void setIsExprClosure() {
michael@0 203 flags_ |= EXPR_CLOSURE;
michael@0 204 }
michael@0 205
michael@0 206 void setArrow() {
michael@0 207 flags_ |= ARROW;
michael@0 208 }
michael@0 209
michael@0 210 JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
michael@0 211 js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); }
michael@0 212 void initAtom(JSAtom *atom) { atom_.init(atom); }
michael@0 213
michael@0 214 JSAtom *displayAtom() const {
michael@0 215 return atom_;
michael@0 216 }
michael@0 217
michael@0 218 void setGuessedAtom(JSAtom *atom) {
michael@0 219 JS_ASSERT(atom_ == nullptr);
michael@0 220 JS_ASSERT(atom != nullptr);
michael@0 221 JS_ASSERT(!hasGuessedAtom());
michael@0 222 atom_ = atom;
michael@0 223 flags_ |= HAS_GUESSED_ATOM;
michael@0 224 }
michael@0 225
michael@0 226 /* uint16_t representation bounds number of call object dynamic slots. */
michael@0 227 enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
michael@0 228
michael@0 229 /*
michael@0 230 * For an interpreted function, accessors for the initial scope object of
michael@0 231 * activations (stack frames) of the function.
michael@0 232 */
michael@0 233 JSObject *environment() const {
michael@0 234 JS_ASSERT(isInterpreted());
michael@0 235 return u.i.env_;
michael@0 236 }
michael@0 237
michael@0 238 void setEnvironment(JSObject *obj) {
michael@0 239 JS_ASSERT(isInterpreted());
michael@0 240 *(js::HeapPtrObject *)&u.i.env_ = obj;
michael@0 241 }
michael@0 242
michael@0 243 void initEnvironment(JSObject *obj) {
michael@0 244 JS_ASSERT(isInterpreted());
michael@0 245 ((js::HeapPtrObject *)&u.i.env_)->init(obj);
michael@0 246 }
michael@0 247
michael@0 248 static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
michael@0 249 static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
michael@0 250 static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
michael@0 251 static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
michael@0 252
michael@0 253 static bool createScriptForLazilyInterpretedFunction(JSContext *cx, js::HandleFunction fun);
michael@0 254 void relazify(JSTracer *trc);
michael@0 255
michael@0 256 // Function Scripts
michael@0 257 //
michael@0 258 // Interpreted functions may either have an explicit JSScript (hasScript())
michael@0 259 // or be lazy with sufficient information to construct the JSScript if
michael@0 260 // necessary (isInterpretedLazy()).
michael@0 261 //
michael@0 262 // A lazy function will have a LazyScript if the function came from parsed
michael@0 263 // source, or nullptr if the function is a clone of a self hosted function.
michael@0 264 //
michael@0 265 // There are several methods to get the script of an interpreted function:
michael@0 266 //
michael@0 267 // - For all interpreted functions, getOrCreateScript() will get the
michael@0 268 // JSScript, delazifying the function if necessary. This is the safest to
michael@0 269 // use, but has extra checks, requires a cx and may trigger a GC.
michael@0 270 //
michael@0 271 // - For inlined functions which may have a LazyScript but whose JSScript
michael@0 272 // is known to exist, existingScriptForInlinedFunction() will get the
michael@0 273 // script and delazify the function if necessary.
michael@0 274 //
michael@0 275 // - For functions known to have a JSScript, nonLazyScript() will get it.
michael@0 276
michael@0 277 JSScript *getOrCreateScript(JSContext *cx) {
michael@0 278 JS_ASSERT(isInterpreted());
michael@0 279 JS_ASSERT(cx);
michael@0 280 if (isInterpretedLazy()) {
michael@0 281 JS::RootedFunction self(cx, this);
michael@0 282 if (!createScriptForLazilyInterpretedFunction(cx, self))
michael@0 283 return nullptr;
michael@0 284 return self->nonLazyScript();
michael@0 285 }
michael@0 286 return nonLazyScript();
michael@0 287 }
michael@0 288
michael@0 289 JSScript *existingScriptForInlinedFunction() {
michael@0 290 MOZ_ASSERT(isInterpreted());
michael@0 291 if (isInterpretedLazy()) {
michael@0 292 // Get the script from the canonical function. Ion used the
michael@0 293 // canonical function to inline the script and because it has
michael@0 294 // Baseline code it has not been relazified. Note that we can't
michael@0 295 // use lazyScript->script_ here as it may be null in some cases,
michael@0 296 // see bug 976536.
michael@0 297 js::LazyScript *lazy = lazyScript();
michael@0 298 JSFunction *fun = lazy->functionNonDelazifying();
michael@0 299 MOZ_ASSERT(fun);
michael@0 300 JSScript *script = fun->nonLazyScript();
michael@0 301
michael@0 302 if (shadowZone()->needsBarrier())
michael@0 303 js::LazyScript::writeBarrierPre(lazy);
michael@0 304
michael@0 305 flags_ &= ~INTERPRETED_LAZY;
michael@0 306 flags_ |= INTERPRETED;
michael@0 307 initScript(script);
michael@0 308 }
michael@0 309 return nonLazyScript();
michael@0 310 }
michael@0 311
michael@0 312 JSScript *nonLazyScript() const {
michael@0 313 JS_ASSERT(hasScript());
michael@0 314 JS_ASSERT(u.i.s.script_);
michael@0 315 return u.i.s.script_;
michael@0 316 }
michael@0 317
michael@0 318 // Returns non-callsited-clone version of this. Use when return
michael@0 319 // value can flow to arbitrary JS (see Bug 944975).
michael@0 320 JSFunction* originalFunction() {
michael@0 321 if (this->hasScript() && this->nonLazyScript()->isCallsiteClone()) {
michael@0 322 return this->nonLazyScript()->donorFunction();
michael@0 323 } else {
michael@0 324 return this;
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 js::HeapPtrScript &mutableScript() {
michael@0 329 JS_ASSERT(isInterpreted());
michael@0 330 return *(js::HeapPtrScript *)&u.i.s.script_;
michael@0 331 }
michael@0 332
michael@0 333 js::LazyScript *lazyScript() const {
michael@0 334 JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
michael@0 335 return u.i.s.lazy_;
michael@0 336 }
michael@0 337
michael@0 338 js::LazyScript *lazyScriptOrNull() const {
michael@0 339 JS_ASSERT(isInterpretedLazy());
michael@0 340 return u.i.s.lazy_;
michael@0 341 }
michael@0 342
michael@0 343 js::GeneratorKind generatorKind() const {
michael@0 344 if (!isInterpreted())
michael@0 345 return js::NotGenerator;
michael@0 346 if (hasScript())
michael@0 347 return nonLazyScript()->generatorKind();
michael@0 348 if (js::LazyScript *lazy = lazyScriptOrNull())
michael@0 349 return lazy->generatorKind();
michael@0 350 JS_ASSERT(isSelfHostedBuiltin());
michael@0 351 return js::NotGenerator;
michael@0 352 }
michael@0 353
michael@0 354 bool isGenerator() const { return generatorKind() != js::NotGenerator; }
michael@0 355
michael@0 356 bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
michael@0 357
michael@0 358 bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
michael@0 359
michael@0 360 void setScript(JSScript *script_) {
michael@0 361 JS_ASSERT(hasScript());
michael@0 362 mutableScript() = script_;
michael@0 363 }
michael@0 364
michael@0 365 void initScript(JSScript *script_) {
michael@0 366 JS_ASSERT(hasScript());
michael@0 367 mutableScript().init(script_);
michael@0 368 }
michael@0 369
michael@0 370 void setUnlazifiedScript(JSScript *script) {
michael@0 371 // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
michael@0 372 // lazy script before it is overwritten here.
michael@0 373 JS_ASSERT(isInterpretedLazy());
michael@0 374 if (!lazyScript()->maybeScript())
michael@0 375 lazyScript()->initScript(script);
michael@0 376 flags_ &= ~INTERPRETED_LAZY;
michael@0 377 flags_ |= INTERPRETED;
michael@0 378 initScript(script);
michael@0 379 }
michael@0 380
michael@0 381 void initLazyScript(js::LazyScript *lazy) {
michael@0 382 JS_ASSERT(isInterpreted());
michael@0 383 flags_ &= ~INTERPRETED;
michael@0 384 flags_ |= INTERPRETED_LAZY;
michael@0 385 u.i.s.lazy_ = lazy;
michael@0 386 }
michael@0 387
michael@0 388 JSNative native() const {
michael@0 389 JS_ASSERT(isNative());
michael@0 390 return u.n.native;
michael@0 391 }
michael@0 392
michael@0 393 JSNative maybeNative() const {
michael@0 394 return isInterpreted() ? nullptr : native();
michael@0 395 }
michael@0 396
michael@0 397 JSParallelNative parallelNative() const {
michael@0 398 JS_ASSERT(hasParallelNative());
michael@0 399 return jitInfo()->parallelNative;
michael@0 400 }
michael@0 401
michael@0 402 JSParallelNative maybeParallelNative() const {
michael@0 403 return hasParallelNative() ? parallelNative() : nullptr;
michael@0 404 }
michael@0 405
michael@0 406 void initNative(js::Native native, const JSJitInfo *jitinfo) {
michael@0 407 JS_ASSERT(native);
michael@0 408 u.n.native = native;
michael@0 409 u.n.jitinfo = jitinfo;
michael@0 410 }
michael@0 411
michael@0 412 const JSJitInfo *jitInfo() const {
michael@0 413 JS_ASSERT(isNative());
michael@0 414 return u.n.jitinfo;
michael@0 415 }
michael@0 416
michael@0 417 void setJitInfo(const JSJitInfo *data) {
michael@0 418 JS_ASSERT(isNative());
michael@0 419 u.n.jitinfo = data;
michael@0 420 }
michael@0 421
michael@0 422 static unsigned offsetOfNativeOrScript() {
michael@0 423 JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.s.script_));
michael@0 424 JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript));
michael@0 425 return offsetof(JSFunction, u.nativeOrScript);
michael@0 426 }
michael@0 427
michael@0 428 #if JS_BITS_PER_WORD == 32
michael@0 429 static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2_BACKGROUND;
michael@0 430 static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
michael@0 431 #else
michael@0 432 static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
michael@0 433 static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8_BACKGROUND;
michael@0 434 #endif
michael@0 435
michael@0 436 inline void trace(JSTracer *trc);
michael@0 437
michael@0 438 /* Bound function accessors. */
michael@0 439
michael@0 440 inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg,
michael@0 441 const js::Value *args, unsigned argslen);
michael@0 442
michael@0 443 JSObject *getBoundFunctionTarget() const {
michael@0 444 JS_ASSERT(isBoundFunction());
michael@0 445
michael@0 446 /* Bound functions abuse |parent| to store their target function. */
michael@0 447 return getParent();
michael@0 448 }
michael@0 449
michael@0 450 const js::Value &getBoundFunctionThis() const;
michael@0 451 const js::Value &getBoundFunctionArgument(unsigned which) const;
michael@0 452 size_t getBoundFunctionArgumentCount() const;
michael@0 453
michael@0 454 private:
michael@0 455 inline js::FunctionExtended *toExtended();
michael@0 456 inline const js::FunctionExtended *toExtended() const;
michael@0 457
michael@0 458 public:
michael@0 459 inline bool isExtended() const {
michael@0 460 JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
michael@0 461 JS_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (tenuredGetAllocKind() == ExtendedFinalizeKind));
michael@0 462 return !!(flags() & EXTENDED);
michael@0 463 }
michael@0 464
michael@0 465 /*
michael@0 466 * Accessors for data stored in extended functions. Use setExtendedSlot if
michael@0 467 * the function has already been initialized. Otherwise use
michael@0 468 * initExtendedSlot.
michael@0 469 */
michael@0 470 inline void initializeExtended();
michael@0 471 inline void initExtendedSlot(size_t which, const js::Value &val);
michael@0 472 inline void setExtendedSlot(size_t which, const js::Value &val);
michael@0 473 inline const js::Value &getExtendedSlot(size_t which) const;
michael@0 474
michael@0 475 /* Constructs a new type for the function if necessary. */
michael@0 476 static bool setTypeForScriptedFunction(js::ExclusiveContext *cx, js::HandleFunction fun,
michael@0 477 bool singleton = false);
michael@0 478
michael@0 479 /* GC support. */
michael@0 480 js::gc::AllocKind getAllocKind() const {
michael@0 481 js::gc::AllocKind kind = FinalizeKind;
michael@0 482 if (isExtended())
michael@0 483 kind = ExtendedFinalizeKind;
michael@0 484 JS_ASSERT_IF(isTenured(), kind == tenuredGetAllocKind());
michael@0 485 return kind;
michael@0 486 }
michael@0 487 };
michael@0 488
michael@0 489 extern JSString *
michael@0 490 fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent);
michael@0 491
michael@0 492 inline JSFunction::Flags
michael@0 493 JSAPIToJSFunctionFlags(unsigned flags)
michael@0 494 {
michael@0 495 return (flags & JSFUN_CONSTRUCTOR)
michael@0 496 ? JSFunction::NATIVE_CTOR
michael@0 497 : JSFunction::NATIVE_FUN;
michael@0 498 }
michael@0 499
michael@0 500 namespace js {
michael@0 501
michael@0 502 extern bool
michael@0 503 Function(JSContext *cx, unsigned argc, Value *vp);
michael@0 504
michael@0 505 extern bool
michael@0 506 Generator(JSContext *cx, unsigned argc, Value *vp);
michael@0 507
michael@0 508 extern JSFunction *
michael@0 509 NewFunction(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs,
michael@0 510 JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
michael@0 511 gc::AllocKind allocKind = JSFunction::FinalizeKind,
michael@0 512 NewObjectKind newKind = GenericObject);
michael@0 513
michael@0 514 // If proto is nullptr, Function.prototype is used instead.
michael@0 515 extern JSFunction *
michael@0 516 NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs,
michael@0 517 JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
michael@0 518 JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind,
michael@0 519 NewObjectKind newKind = GenericObject);
michael@0 520
michael@0 521 extern JSFunction *
michael@0 522 DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native,
michael@0 523 unsigned nargs, unsigned flags,
michael@0 524 gc::AllocKind allocKind = JSFunction::FinalizeKind,
michael@0 525 NewObjectKind newKind = GenericObject);
michael@0 526
michael@0 527 bool
michael@0 528 FunctionHasResolveHook(const JSAtomState &atomState, PropertyName *name);
michael@0 529
michael@0 530 extern bool
michael@0 531 fun_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp);
michael@0 532
michael@0 533 // ES6 9.2.5 IsConstructor
michael@0 534 bool IsConstructor(const Value &v);
michael@0 535
michael@0 536 /*
michael@0 537 * Function extended with reserved slots for use by various kinds of functions.
michael@0 538 * Most functions do not have these extensions, but enough do that efficient
michael@0 539 * storage is required (no malloc'ed reserved slots).
michael@0 540 */
michael@0 541 class FunctionExtended : public JSFunction
michael@0 542 {
michael@0 543 public:
michael@0 544 static const unsigned NUM_EXTENDED_SLOTS = 2;
michael@0 545
michael@0 546 /* Arrow functions store their lexical |this| in the first extended slot. */
michael@0 547 static const unsigned ARROW_THIS_SLOT = 0;
michael@0 548
michael@0 549 static inline size_t offsetOfExtendedSlot(unsigned which) {
michael@0 550 MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
michael@0 551 return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue);
michael@0 552 }
michael@0 553 static inline size_t offsetOfArrowThisSlot() {
michael@0 554 return offsetOfExtendedSlot(ARROW_THIS_SLOT);
michael@0 555 }
michael@0 556
michael@0 557 private:
michael@0 558 friend class JSFunction;
michael@0 559
michael@0 560 /* Reserved slots available for storage by particular native functions. */
michael@0 561 HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
michael@0 562 };
michael@0 563
michael@0 564 extern JSFunction *
michael@0 565 CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
michael@0 566 gc::AllocKind kind = JSFunction::FinalizeKind,
michael@0 567 NewObjectKind newKindArg = GenericObject);
michael@0 568
michael@0 569
michael@0 570 extern bool
michael@0 571 FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length,
michael@0 572 size_t *bodyStart, size_t *bodyEnd);
michael@0 573
michael@0 574 } // namespace js
michael@0 575
michael@0 576 inline js::FunctionExtended *
michael@0 577 JSFunction::toExtended()
michael@0 578 {
michael@0 579 JS_ASSERT(isExtended());
michael@0 580 return static_cast<js::FunctionExtended *>(this);
michael@0 581 }
michael@0 582
michael@0 583 inline const js::FunctionExtended *
michael@0 584 JSFunction::toExtended() const
michael@0 585 {
michael@0 586 JS_ASSERT(isExtended());
michael@0 587 return static_cast<const js::FunctionExtended *>(this);
michael@0 588 }
michael@0 589
michael@0 590 inline void
michael@0 591 JSFunction::initializeExtended()
michael@0 592 {
michael@0 593 JS_ASSERT(isExtended());
michael@0 594
michael@0 595 JS_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
michael@0 596 toExtended()->extendedSlots[0].init(js::UndefinedValue());
michael@0 597 toExtended()->extendedSlots[1].init(js::UndefinedValue());
michael@0 598 }
michael@0 599
michael@0 600 inline void
michael@0 601 JSFunction::initExtendedSlot(size_t which, const js::Value &val)
michael@0 602 {
michael@0 603 JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
michael@0 604 toExtended()->extendedSlots[which].init(val);
michael@0 605 }
michael@0 606
michael@0 607 inline void
michael@0 608 JSFunction::setExtendedSlot(size_t which, const js::Value &val)
michael@0 609 {
michael@0 610 JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
michael@0 611 toExtended()->extendedSlots[which] = val;
michael@0 612 }
michael@0 613
michael@0 614 inline const js::Value &
michael@0 615 JSFunction::getExtendedSlot(size_t which) const
michael@0 616 {
michael@0 617 JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
michael@0 618 return toExtended()->extendedSlots[which];
michael@0 619 }
michael@0 620
michael@0 621 namespace js {
michael@0 622
michael@0 623 JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen);
michael@0 624
michael@0 625 template<XDRMode mode>
michael@0 626 bool
michael@0 627 XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope,
michael@0 628 HandleScript enclosingScript, MutableHandleObject objp);
michael@0 629
michael@0 630 extern JSObject *
michael@0 631 CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun);
michael@0 632
michael@0 633 /*
michael@0 634 * Report an error that call.thisv is not compatible with the specified class,
michael@0 635 * assuming that the method (clasp->name).prototype.<name of callee function>
michael@0 636 * is what was called.
michael@0 637 */
michael@0 638 extern void
michael@0 639 ReportIncompatibleMethod(JSContext *cx, CallReceiver call, const Class *clasp);
michael@0 640
michael@0 641 /*
michael@0 642 * Report an error that call.thisv is not an acceptable this for the callee
michael@0 643 * function.
michael@0 644 */
michael@0 645 extern void
michael@0 646 ReportIncompatible(JSContext *cx, CallReceiver call);
michael@0 647
michael@0 648 bool
michael@0 649 CallOrConstructBoundFunction(JSContext *, unsigned, js::Value *);
michael@0 650
michael@0 651 extern const JSFunctionSpec function_methods[];
michael@0 652
michael@0 653 } /* namespace js */
michael@0 654
michael@0 655 extern bool
michael@0 656 js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
michael@0 657
michael@0 658 extern bool
michael@0 659 js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
michael@0 660
michael@0 661 extern JSObject*
michael@0 662 js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg,
michael@0 663 js::Value *boundArgs, unsigned argslen);
michael@0 664
michael@0 665 #ifdef DEBUG
michael@0 666 namespace JS {
michael@0 667 namespace detail {
michael@0 668
michael@0 669 JS_PUBLIC_API(void)
michael@0 670 CheckIsValidConstructible(Value calleev);
michael@0 671
michael@0 672 } // namespace detail
michael@0 673 } // namespace JS
michael@0 674 #endif
michael@0 675
michael@0 676 #endif /* jsfun_h */

mercurial