michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jsfun_h michael@0: #define jsfun_h michael@0: michael@0: /* michael@0: * JS function definitions. michael@0: */ michael@0: michael@0: #include "jsobj.h" michael@0: #include "jsscript.h" michael@0: #include "jstypes.h" michael@0: michael@0: namespace js { michael@0: class FunctionExtended; michael@0: michael@0: typedef JSNative Native; michael@0: typedef JSParallelNative ParallelNative; michael@0: typedef JSThreadSafeNative ThreadSafeNative; michael@0: } michael@0: michael@0: struct JSAtomState; michael@0: michael@0: class JSFunction : public JSObject michael@0: { michael@0: public: michael@0: static const js::Class class_; michael@0: michael@0: enum Flags { michael@0: INTERPRETED = 0x0001, /* function has a JSScript and environment. */ michael@0: NATIVE_CTOR = 0x0002, /* native that can be called as a constructor */ michael@0: EXTENDED = 0x0004, /* structure is FunctionExtended */ michael@0: IS_FUN_PROTO = 0x0010, /* function is Function.prototype for some global object */ michael@0: EXPR_CLOSURE = 0x0020, /* expression closure: function(x) x*x */ michael@0: HAS_GUESSED_ATOM = 0x0040, /* function had no explicit name, but a michael@0: name was guessed for it anyway */ michael@0: LAMBDA = 0x0080, /* function comes from a FunctionExpression, ArrowFunction, or michael@0: Function() call (not a FunctionDeclaration or nonstandard michael@0: function-statement) */ michael@0: SELF_HOSTED = 0x0100, /* function is self-hosted builtin and must not be michael@0: decompilable nor constructible. */ michael@0: SELF_HOSTED_CTOR = 0x0200, /* function is self-hosted builtin constructor and michael@0: must be constructible but not decompilable. */ michael@0: HAS_REST = 0x0400, /* function has a rest (...) parameter */ michael@0: // 0x0800 is available michael@0: INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */ michael@0: ARROW = 0x2000, /* ES6 '(args) => body' syntax */ michael@0: michael@0: /* Derived Flags values for convenience: */ michael@0: NATIVE_FUN = 0, michael@0: NATIVE_LAMBDA_FUN = NATIVE_FUN | LAMBDA, michael@0: INTERPRETED_LAMBDA = INTERPRETED | LAMBDA, michael@0: INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW michael@0: }; michael@0: michael@0: static void staticAsserts() { michael@0: JS_STATIC_ASSERT(INTERPRETED == JS_FUNCTION_INTERPRETED_BIT); michael@0: static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function), michael@0: "shadow interface must match actual interface"); michael@0: } michael@0: michael@0: private: michael@0: uint16_t nargs_; /* number of formal arguments michael@0: (including defaults and the rest parameter unlike f.length) */ michael@0: uint16_t flags_; /* bitfield composed of the above Flags enum */ michael@0: union U { michael@0: class Native { michael@0: friend class JSFunction; michael@0: js::Native native; /* native method pointer or null */ michael@0: const JSJitInfo *jitinfo; /* Information about this function to be michael@0: used by the JIT; michael@0: use the accessor! */ michael@0: } n; michael@0: struct Scripted { michael@0: union { michael@0: JSScript *script_; /* interpreted bytecode descriptor or null; michael@0: use the accessor! */ michael@0: js::LazyScript *lazy_; /* lazily compiled script, or nullptr */ michael@0: } s; michael@0: JSObject *env_; /* environment for new activations; michael@0: use the accessor! */ michael@0: } i; michael@0: void *nativeOrScript; michael@0: } u; michael@0: js::HeapPtrAtom atom_; /* name for diagnostics and decompiling */ michael@0: michael@0: public: michael@0: michael@0: /* Call objects must be created for each invocation of a heavyweight function. */ michael@0: bool isHeavyweight() const { michael@0: JS_ASSERT(!isInterpretedLazy()); michael@0: michael@0: if (isNative()) michael@0: return false; michael@0: michael@0: // Note: this should be kept in sync with FunctionBox::isHeavyweight(). michael@0: return nonLazyScript()->hasAnyAliasedBindings() || michael@0: nonLazyScript()->funHasExtensibleScope() || michael@0: nonLazyScript()->funNeedsDeclEnvObject() || michael@0: isGenerator(); michael@0: } michael@0: michael@0: size_t nargs() const { michael@0: return nargs_; michael@0: } michael@0: michael@0: uint16_t flags() const { michael@0: return flags_; michael@0: } michael@0: michael@0: /* A function can be classified as either native (C++) or interpreted (JS): */ michael@0: bool isInterpreted() const { return flags() & (INTERPRETED | INTERPRETED_LAZY); } michael@0: bool isNative() const { return !isInterpreted(); } michael@0: michael@0: /* Possible attributes of a native function: */ michael@0: bool isNativeConstructor() const { return flags() & NATIVE_CTOR; } michael@0: michael@0: /* Possible attributes of an interpreted function: */ michael@0: bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; } michael@0: bool isExprClosure() const { return flags() & EXPR_CLOSURE; } michael@0: bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; } michael@0: bool isLambda() const { return flags() & LAMBDA; } michael@0: bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; } michael@0: bool isSelfHostedConstructor() const { return flags() & SELF_HOSTED_CTOR; } michael@0: bool hasRest() const { return flags() & HAS_REST; } michael@0: michael@0: bool isInterpretedLazy() const { michael@0: return flags() & INTERPRETED_LAZY; michael@0: } michael@0: bool hasScript() const { michael@0: return flags() & INTERPRETED; michael@0: } michael@0: michael@0: bool hasJITCode() const { michael@0: if (!hasScript()) michael@0: return false; michael@0: michael@0: return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript(); michael@0: } michael@0: michael@0: // Arrow functions store their lexical |this| in the first extended slot. michael@0: bool isArrow() const { return flags() & ARROW; } michael@0: michael@0: /* Compound attributes: */ michael@0: bool isBuiltin() const { michael@0: return isNative() || isSelfHostedBuiltin(); michael@0: } michael@0: bool isInterpretedConstructor() const { michael@0: // Note: the JITs inline this check, so be careful when making changes michael@0: // here. See IonMacroAssembler::branchIfNotInterpretedConstructor. michael@0: return isInterpreted() && !isFunctionPrototype() && !isArrow() && michael@0: (!isSelfHostedBuiltin() || isSelfHostedConstructor()); michael@0: } michael@0: bool isNamedLambda() const { michael@0: return isLambda() && displayAtom() && !hasGuessedAtom(); michael@0: } michael@0: bool hasParallelNative() const { michael@0: return isNative() && jitInfo() && jitInfo()->hasParallelNative(); michael@0: } michael@0: michael@0: bool isBuiltinFunctionConstructor(); michael@0: michael@0: /* Returns the strictness of this function, which must be interpreted. */ michael@0: bool strict() const { michael@0: return nonLazyScript()->strict(); michael@0: } michael@0: michael@0: void setFlags(uint16_t flags) { michael@0: this->flags_ = flags; michael@0: } michael@0: michael@0: // Can be called multiple times by the parser. michael@0: void setArgCount(uint16_t nargs) { michael@0: this->nargs_ = nargs; michael@0: } michael@0: michael@0: // Can be called multiple times by the parser. michael@0: void setHasRest() { michael@0: flags_ |= HAS_REST; michael@0: } michael@0: michael@0: void setIsSelfHostedBuiltin() { michael@0: JS_ASSERT(!isSelfHostedBuiltin()); michael@0: flags_ |= SELF_HOSTED; michael@0: } michael@0: michael@0: void setIsSelfHostedConstructor() { michael@0: JS_ASSERT(!isSelfHostedConstructor()); michael@0: flags_ |= SELF_HOSTED_CTOR; michael@0: } michael@0: michael@0: void setIsFunctionPrototype() { michael@0: JS_ASSERT(!isFunctionPrototype()); michael@0: flags_ |= IS_FUN_PROTO; michael@0: } michael@0: michael@0: // Can be called multiple times by the parser. michael@0: void setIsExprClosure() { michael@0: flags_ |= EXPR_CLOSURE; michael@0: } michael@0: michael@0: void setArrow() { michael@0: flags_ |= ARROW; michael@0: } michael@0: michael@0: JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } michael@0: js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); } michael@0: void initAtom(JSAtom *atom) { atom_.init(atom); } michael@0: michael@0: JSAtom *displayAtom() const { michael@0: return atom_; michael@0: } michael@0: michael@0: void setGuessedAtom(JSAtom *atom) { michael@0: JS_ASSERT(atom_ == nullptr); michael@0: JS_ASSERT(atom != nullptr); michael@0: JS_ASSERT(!hasGuessedAtom()); michael@0: atom_ = atom; michael@0: flags_ |= HAS_GUESSED_ATOM; michael@0: } michael@0: michael@0: /* uint16_t representation bounds number of call object dynamic slots. */ michael@0: enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) }; michael@0: michael@0: /* michael@0: * For an interpreted function, accessors for the initial scope object of michael@0: * activations (stack frames) of the function. michael@0: */ michael@0: JSObject *environment() const { michael@0: JS_ASSERT(isInterpreted()); michael@0: return u.i.env_; michael@0: } michael@0: michael@0: void setEnvironment(JSObject *obj) { michael@0: JS_ASSERT(isInterpreted()); michael@0: *(js::HeapPtrObject *)&u.i.env_ = obj; michael@0: } michael@0: michael@0: void initEnvironment(JSObject *obj) { michael@0: JS_ASSERT(isInterpreted()); michael@0: ((js::HeapPtrObject *)&u.i.env_)->init(obj); michael@0: } michael@0: michael@0: static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); } michael@0: static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); } michael@0: static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); } michael@0: static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); } michael@0: michael@0: static bool createScriptForLazilyInterpretedFunction(JSContext *cx, js::HandleFunction fun); michael@0: void relazify(JSTracer *trc); michael@0: michael@0: // Function Scripts michael@0: // michael@0: // Interpreted functions may either have an explicit JSScript (hasScript()) michael@0: // or be lazy with sufficient information to construct the JSScript if michael@0: // necessary (isInterpretedLazy()). michael@0: // michael@0: // A lazy function will have a LazyScript if the function came from parsed michael@0: // source, or nullptr if the function is a clone of a self hosted function. michael@0: // michael@0: // There are several methods to get the script of an interpreted function: michael@0: // michael@0: // - For all interpreted functions, getOrCreateScript() will get the michael@0: // JSScript, delazifying the function if necessary. This is the safest to michael@0: // use, but has extra checks, requires a cx and may trigger a GC. michael@0: // michael@0: // - For inlined functions which may have a LazyScript but whose JSScript michael@0: // is known to exist, existingScriptForInlinedFunction() will get the michael@0: // script and delazify the function if necessary. michael@0: // michael@0: // - For functions known to have a JSScript, nonLazyScript() will get it. michael@0: michael@0: JSScript *getOrCreateScript(JSContext *cx) { michael@0: JS_ASSERT(isInterpreted()); michael@0: JS_ASSERT(cx); michael@0: if (isInterpretedLazy()) { michael@0: JS::RootedFunction self(cx, this); michael@0: if (!createScriptForLazilyInterpretedFunction(cx, self)) michael@0: return nullptr; michael@0: return self->nonLazyScript(); michael@0: } michael@0: return nonLazyScript(); michael@0: } michael@0: michael@0: JSScript *existingScriptForInlinedFunction() { michael@0: MOZ_ASSERT(isInterpreted()); michael@0: if (isInterpretedLazy()) { michael@0: // Get the script from the canonical function. Ion used the michael@0: // canonical function to inline the script and because it has michael@0: // Baseline code it has not been relazified. Note that we can't michael@0: // use lazyScript->script_ here as it may be null in some cases, michael@0: // see bug 976536. michael@0: js::LazyScript *lazy = lazyScript(); michael@0: JSFunction *fun = lazy->functionNonDelazifying(); michael@0: MOZ_ASSERT(fun); michael@0: JSScript *script = fun->nonLazyScript(); michael@0: michael@0: if (shadowZone()->needsBarrier()) michael@0: js::LazyScript::writeBarrierPre(lazy); michael@0: michael@0: flags_ &= ~INTERPRETED_LAZY; michael@0: flags_ |= INTERPRETED; michael@0: initScript(script); michael@0: } michael@0: return nonLazyScript(); michael@0: } michael@0: michael@0: JSScript *nonLazyScript() const { michael@0: JS_ASSERT(hasScript()); michael@0: JS_ASSERT(u.i.s.script_); michael@0: return u.i.s.script_; michael@0: } michael@0: michael@0: // Returns non-callsited-clone version of this. Use when return michael@0: // value can flow to arbitrary JS (see Bug 944975). michael@0: JSFunction* originalFunction() { michael@0: if (this->hasScript() && this->nonLazyScript()->isCallsiteClone()) { michael@0: return this->nonLazyScript()->donorFunction(); michael@0: } else { michael@0: return this; michael@0: } michael@0: } michael@0: michael@0: js::HeapPtrScript &mutableScript() { michael@0: JS_ASSERT(isInterpreted()); michael@0: return *(js::HeapPtrScript *)&u.i.s.script_; michael@0: } michael@0: michael@0: js::LazyScript *lazyScript() const { michael@0: JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_); michael@0: return u.i.s.lazy_; michael@0: } michael@0: michael@0: js::LazyScript *lazyScriptOrNull() const { michael@0: JS_ASSERT(isInterpretedLazy()); michael@0: return u.i.s.lazy_; michael@0: } michael@0: michael@0: js::GeneratorKind generatorKind() const { michael@0: if (!isInterpreted()) michael@0: return js::NotGenerator; michael@0: if (hasScript()) michael@0: return nonLazyScript()->generatorKind(); michael@0: if (js::LazyScript *lazy = lazyScriptOrNull()) michael@0: return lazy->generatorKind(); michael@0: JS_ASSERT(isSelfHostedBuiltin()); michael@0: return js::NotGenerator; michael@0: } michael@0: michael@0: bool isGenerator() const { return generatorKind() != js::NotGenerator; } michael@0: michael@0: bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; } michael@0: michael@0: bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } michael@0: michael@0: void setScript(JSScript *script_) { michael@0: JS_ASSERT(hasScript()); michael@0: mutableScript() = script_; michael@0: } michael@0: michael@0: void initScript(JSScript *script_) { michael@0: JS_ASSERT(hasScript()); michael@0: mutableScript().init(script_); michael@0: } michael@0: michael@0: void setUnlazifiedScript(JSScript *script) { michael@0: // Note: createScriptForLazilyInterpretedFunction triggers a barrier on michael@0: // lazy script before it is overwritten here. michael@0: JS_ASSERT(isInterpretedLazy()); michael@0: if (!lazyScript()->maybeScript()) michael@0: lazyScript()->initScript(script); michael@0: flags_ &= ~INTERPRETED_LAZY; michael@0: flags_ |= INTERPRETED; michael@0: initScript(script); michael@0: } michael@0: michael@0: void initLazyScript(js::LazyScript *lazy) { michael@0: JS_ASSERT(isInterpreted()); michael@0: flags_ &= ~INTERPRETED; michael@0: flags_ |= INTERPRETED_LAZY; michael@0: u.i.s.lazy_ = lazy; michael@0: } michael@0: michael@0: JSNative native() const { michael@0: JS_ASSERT(isNative()); michael@0: return u.n.native; michael@0: } michael@0: michael@0: JSNative maybeNative() const { michael@0: return isInterpreted() ? nullptr : native(); michael@0: } michael@0: michael@0: JSParallelNative parallelNative() const { michael@0: JS_ASSERT(hasParallelNative()); michael@0: return jitInfo()->parallelNative; michael@0: } michael@0: michael@0: JSParallelNative maybeParallelNative() const { michael@0: return hasParallelNative() ? parallelNative() : nullptr; michael@0: } michael@0: michael@0: void initNative(js::Native native, const JSJitInfo *jitinfo) { michael@0: JS_ASSERT(native); michael@0: u.n.native = native; michael@0: u.n.jitinfo = jitinfo; michael@0: } michael@0: michael@0: const JSJitInfo *jitInfo() const { michael@0: JS_ASSERT(isNative()); michael@0: return u.n.jitinfo; michael@0: } michael@0: michael@0: void setJitInfo(const JSJitInfo *data) { michael@0: JS_ASSERT(isNative()); michael@0: u.n.jitinfo = data; michael@0: } michael@0: michael@0: static unsigned offsetOfNativeOrScript() { michael@0: JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.s.script_)); michael@0: JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript)); michael@0: return offsetof(JSFunction, u.nativeOrScript); michael@0: } michael@0: michael@0: #if JS_BITS_PER_WORD == 32 michael@0: static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2_BACKGROUND; michael@0: static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND; michael@0: #else michael@0: static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND; michael@0: static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8_BACKGROUND; michael@0: #endif michael@0: michael@0: inline void trace(JSTracer *trc); michael@0: michael@0: /* Bound function accessors. */ michael@0: michael@0: inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg, michael@0: const js::Value *args, unsigned argslen); michael@0: michael@0: JSObject *getBoundFunctionTarget() const { michael@0: JS_ASSERT(isBoundFunction()); michael@0: michael@0: /* Bound functions abuse |parent| to store their target function. */ michael@0: return getParent(); michael@0: } michael@0: michael@0: const js::Value &getBoundFunctionThis() const; michael@0: const js::Value &getBoundFunctionArgument(unsigned which) const; michael@0: size_t getBoundFunctionArgumentCount() const; michael@0: michael@0: private: michael@0: inline js::FunctionExtended *toExtended(); michael@0: inline const js::FunctionExtended *toExtended() const; michael@0: michael@0: public: michael@0: inline bool isExtended() const { michael@0: JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind); michael@0: JS_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (tenuredGetAllocKind() == ExtendedFinalizeKind)); michael@0: return !!(flags() & EXTENDED); michael@0: } michael@0: michael@0: /* michael@0: * Accessors for data stored in extended functions. Use setExtendedSlot if michael@0: * the function has already been initialized. Otherwise use michael@0: * initExtendedSlot. michael@0: */ michael@0: inline void initializeExtended(); michael@0: inline void initExtendedSlot(size_t which, const js::Value &val); michael@0: inline void setExtendedSlot(size_t which, const js::Value &val); michael@0: inline const js::Value &getExtendedSlot(size_t which) const; michael@0: michael@0: /* Constructs a new type for the function if necessary. */ michael@0: static bool setTypeForScriptedFunction(js::ExclusiveContext *cx, js::HandleFunction fun, michael@0: bool singleton = false); michael@0: michael@0: /* GC support. */ michael@0: js::gc::AllocKind getAllocKind() const { michael@0: js::gc::AllocKind kind = FinalizeKind; michael@0: if (isExtended()) michael@0: kind = ExtendedFinalizeKind; michael@0: JS_ASSERT_IF(isTenured(), kind == tenuredGetAllocKind()); michael@0: return kind; michael@0: } michael@0: }; michael@0: michael@0: extern JSString * michael@0: fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent); michael@0: michael@0: inline JSFunction::Flags michael@0: JSAPIToJSFunctionFlags(unsigned flags) michael@0: { michael@0: return (flags & JSFUN_CONSTRUCTOR) michael@0: ? JSFunction::NATIVE_CTOR michael@0: : JSFunction::NATIVE_FUN; michael@0: } michael@0: michael@0: namespace js { michael@0: michael@0: extern bool michael@0: Function(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: extern bool michael@0: Generator(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: extern JSFunction * michael@0: NewFunction(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs, michael@0: JSFunction::Flags flags, HandleObject parent, HandleAtom atom, michael@0: gc::AllocKind allocKind = JSFunction::FinalizeKind, michael@0: NewObjectKind newKind = GenericObject); michael@0: michael@0: // If proto is nullptr, Function.prototype is used instead. michael@0: extern JSFunction * michael@0: NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs, michael@0: JSFunction::Flags flags, HandleObject parent, HandleAtom atom, michael@0: JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind, michael@0: NewObjectKind newKind = GenericObject); michael@0: michael@0: extern JSFunction * michael@0: DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native, michael@0: unsigned nargs, unsigned flags, michael@0: gc::AllocKind allocKind = JSFunction::FinalizeKind, michael@0: NewObjectKind newKind = GenericObject); michael@0: michael@0: bool michael@0: FunctionHasResolveHook(const JSAtomState &atomState, PropertyName *name); michael@0: michael@0: extern bool michael@0: fun_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp); michael@0: michael@0: // ES6 9.2.5 IsConstructor michael@0: bool IsConstructor(const Value &v); michael@0: michael@0: /* michael@0: * Function extended with reserved slots for use by various kinds of functions. michael@0: * Most functions do not have these extensions, but enough do that efficient michael@0: * storage is required (no malloc'ed reserved slots). michael@0: */ michael@0: class FunctionExtended : public JSFunction michael@0: { michael@0: public: michael@0: static const unsigned NUM_EXTENDED_SLOTS = 2; michael@0: michael@0: /* Arrow functions store their lexical |this| in the first extended slot. */ michael@0: static const unsigned ARROW_THIS_SLOT = 0; michael@0: michael@0: static inline size_t offsetOfExtendedSlot(unsigned which) { michael@0: MOZ_ASSERT(which < NUM_EXTENDED_SLOTS); michael@0: return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue); michael@0: } michael@0: static inline size_t offsetOfArrowThisSlot() { michael@0: return offsetOfExtendedSlot(ARROW_THIS_SLOT); michael@0: } michael@0: michael@0: private: michael@0: friend class JSFunction; michael@0: michael@0: /* Reserved slots available for storage by particular native functions. */ michael@0: HeapValue extendedSlots[NUM_EXTENDED_SLOTS]; michael@0: }; michael@0: michael@0: extern JSFunction * michael@0: CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, michael@0: gc::AllocKind kind = JSFunction::FinalizeKind, michael@0: NewObjectKind newKindArg = GenericObject); michael@0: michael@0: michael@0: extern bool michael@0: FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length, michael@0: size_t *bodyStart, size_t *bodyEnd); michael@0: michael@0: } // namespace js michael@0: michael@0: inline js::FunctionExtended * michael@0: JSFunction::toExtended() michael@0: { michael@0: JS_ASSERT(isExtended()); michael@0: return static_cast(this); michael@0: } michael@0: michael@0: inline const js::FunctionExtended * michael@0: JSFunction::toExtended() const michael@0: { michael@0: JS_ASSERT(isExtended()); michael@0: return static_cast(this); michael@0: } michael@0: michael@0: inline void michael@0: JSFunction::initializeExtended() michael@0: { michael@0: JS_ASSERT(isExtended()); michael@0: michael@0: JS_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2); michael@0: toExtended()->extendedSlots[0].init(js::UndefinedValue()); michael@0: toExtended()->extendedSlots[1].init(js::UndefinedValue()); michael@0: } michael@0: michael@0: inline void michael@0: JSFunction::initExtendedSlot(size_t which, const js::Value &val) michael@0: { michael@0: JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); michael@0: toExtended()->extendedSlots[which].init(val); michael@0: } michael@0: michael@0: inline void michael@0: JSFunction::setExtendedSlot(size_t which, const js::Value &val) michael@0: { michael@0: JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); michael@0: toExtended()->extendedSlots[which] = val; michael@0: } michael@0: michael@0: inline const js::Value & michael@0: JSFunction::getExtendedSlot(size_t which) const michael@0: { michael@0: JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); michael@0: return toExtended()->extendedSlots[which]; michael@0: } michael@0: michael@0: namespace js { michael@0: michael@0: JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen); michael@0: michael@0: template michael@0: bool michael@0: XDRInterpretedFunction(XDRState *xdr, HandleObject enclosingScope, michael@0: HandleScript enclosingScript, MutableHandleObject objp); michael@0: michael@0: extern JSObject * michael@0: CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun); michael@0: michael@0: /* michael@0: * Report an error that call.thisv is not compatible with the specified class, michael@0: * assuming that the method (clasp->name).prototype. michael@0: * is what was called. michael@0: */ michael@0: extern void michael@0: ReportIncompatibleMethod(JSContext *cx, CallReceiver call, const Class *clasp); michael@0: michael@0: /* michael@0: * Report an error that call.thisv is not an acceptable this for the callee michael@0: * function. michael@0: */ michael@0: extern void michael@0: ReportIncompatible(JSContext *cx, CallReceiver call); michael@0: michael@0: bool michael@0: CallOrConstructBoundFunction(JSContext *, unsigned, js::Value *); michael@0: michael@0: extern const JSFunctionSpec function_methods[]; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern bool michael@0: js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: extern bool michael@0: js_fun_call(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: extern JSObject* michael@0: js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg, michael@0: js::Value *boundArgs, unsigned argslen); michael@0: michael@0: #ifdef DEBUG michael@0: namespace JS { michael@0: namespace detail { michael@0: michael@0: JS_PUBLIC_API(void) michael@0: CheckIsValidConstructible(Value calleev); michael@0: michael@0: } // namespace detail michael@0: } // namespace JS michael@0: #endif michael@0: michael@0: #endif /* jsfun_h */