#ifndef vm_JSFunction_h
#define vm_JSFunction_h
#include "jstypes.h"
#include "vm/JSObject.h"
#include "vm/JSScript.h"
namespace js {
class FunctionExtended;
typedef JSNative Native;
}
static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
static const char FunctionConstructorMedialSigils[] = ") {\n";
static const char FunctionConstructorFinalBrace[] = "\n}";
enum class FunctionPrefixKind { None, Get, Set };
class JSFunction : public js::NativeObject {
public:
static const js::Class class_;
enum FunctionKind {
NormalFunction = 0,
Arrow,
Method,
ClassConstructor,
Getter,
Setter,
AsmJS,
FunctionKindLimit
};
enum Flags {
INTERPRETED = 0x0001,
CONSTRUCTOR = 0x0002,
EXTENDED = 0x0004,
BOUND_FUN = 0x0008,
WASM_OPTIMIZED = 0x0010,
HAS_GUESSED_ATOM = 0x0020,
HAS_BOUND_FUNCTION_NAME_PREFIX =
0x0020,
LAMBDA = 0x0040,
SELF_HOSTED =
0x0080,
HAS_INFERRED_NAME = 0x0100,
INTERPRETED_LAZY =
0x0200,
RESOLVED_LENGTH =
0x0400,
RESOLVED_NAME = 0x0800,
NEW_SCRIPT_CLEARED =
0x1000,
FUNCTION_KIND_SHIFT = 13,
FUNCTION_KIND_MASK = 0x7 << FUNCTION_KIND_SHIFT,
ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
NATIVE_FUN = 0,
NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
ASMJS_NATIVE = ASMJS_KIND | NATIVE_FUN,
WASM_FUN = NATIVE_FUN | WASM_OPTIMIZED,
INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
INTERPRETED_CLASS_CONSTRUCTOR =
INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = INTERPRETED | LAMBDA,
INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED,
NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
STABLE_ACROSS_CLONES =
CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK
};
static_assert((INTERPRETED | INTERPRETED_LAZY) ==
js::JS_FUNCTION_INTERPRETED_BITS,
"jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <=
FUNCTION_KIND_MASK,
"FunctionKind doesn't fit into flags_");
private:
uint16_t
nargs_;
uint16_t flags_;
union U {
class {
friend class JSFunction;
js::Native func_;
union {
const JSJitInfo* jitInfo_;
size_t asmJSFuncIndex_;
void** wasmJitEntry_;
} extra;
} native;
struct {
JSObject* env_;
union {
JSScript* script_;
js::LazyScript* lazy_;
} s;
} scripted;
} u;
js::GCPtrAtom atom_;
public:
static inline JS::Result<JSFunction*, JS::OOM&> create(
JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
js::HandleShape shape, js::HandleObjectGroup group);
bool needsCallObject() const {
MOZ_ASSERT(!isInterpretedLazy());
if (isNative()) {
return false;
}
MOZ_ASSERT_IF(nonLazyScript()->funHasExtensibleScope() ||
nonLazyScript()->needsHomeObject() ||
nonLazyScript()->isDerivedClassConstructor() ||
isGenerator() || isAsync(),
nonLazyScript()->bodyScope()->hasEnvironment());
return nonLazyScript()->bodyScope()->hasEnvironment();
}
bool needsExtraBodyVarEnvironment() const;
bool needsNamedLambdaEnvironment() const;
bool needsFunctionEnvironmentObjects() const {
bool res = nonLazyScript()->needsFunctionEnvironmentObjects();
MOZ_ASSERT(res == (needsCallObject() || needsNamedLambdaEnvironment()));
return res;
}
bool needsSomeEnvironmentObject() const {
return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment();
}
static constexpr size_t NArgsBits = sizeof(nargs_) * CHAR_BIT;
size_t nargs() const { return nargs_; }
uint16_t flags() const { return flags_; }
FunctionKind kind() const {
return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >>
FUNCTION_KIND_SHIFT);
}
bool isInterpreted() const {
return flags() & (INTERPRETED | INTERPRETED_LAZY);
}
bool isNative() const { return !isInterpreted(); }
bool isConstructor() const { return flags() & CONSTRUCTOR; }
bool isAsmJSNative() const { return kind() == AsmJS; }
bool isWasmOptimized() const { return (flags() & WASM_OPTIMIZED); }
bool isBuiltinNative() const {
return isNativeWithCppEntry() && !isAsmJSNative();
}
bool isNativeWithJitEntry() const { return isNative() && isWasmOptimized(); }
bool isNativeWithCppEntry() const { return isNative() && !isWasmOptimized(); }
bool isBoundFunction() const { return flags() & BOUND_FUN; }
bool hasInferredName() const { return flags() & HAS_INFERRED_NAME; }
bool hasGuessedAtom() const {
static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX,
"HAS_GUESSED_ATOM is unused for bound functions");
return (flags() & (HAS_GUESSED_ATOM | BOUND_FUN)) == HAS_GUESSED_ATOM;
}
bool hasBoundFunctionNamePrefix() const {
static_assert(
HAS_BOUND_FUNCTION_NAME_PREFIX == HAS_GUESSED_ATOM,
"HAS_BOUND_FUNCTION_NAME_PREFIX is only used for bound functions");
MOZ_ASSERT(isBoundFunction());
return flags() & HAS_BOUND_FUNCTION_NAME_PREFIX;
}
bool isLambda() const { return flags() & LAMBDA; }
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
bool hasScript() const { return flags() & INTERPRETED; }
bool isArrow() const { return kind() == Arrow; }
bool isMethod() const {
return kind() == Method || kind() == ClassConstructor;
}
bool isClassConstructor() const { return kind() == ClassConstructor; }
bool isGetter() const { return kind() == Getter; }
bool isSetter() const { return kind() == Setter; }
bool allowSuperProperty() const {
return isMethod() || isGetter() || isSetter();
}
bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; }
bool hasResolvedName() const { return flags() & RESOLVED_NAME; }
bool isSelfHostedOrIntrinsic() const { return flags() & SELF_HOSTED; }
bool isSelfHostedBuiltin() const {
return isSelfHostedOrIntrinsic() && !isNative();
}
bool isIntrinsic() const { return isSelfHostedOrIntrinsic() && isNative(); }
bool hasJITCode() const {
if (!hasScript()) {
return false;
}
return nonLazyScript()->hasBaselineScript() ||
nonLazyScript()->hasIonScript();
}
bool hasJitEntry() const { return hasScript() || isNativeWithJitEntry(); }
bool isBuiltin() const {
return isBuiltinNative() || isNativeWithJitEntry() || isSelfHostedBuiltin();
}
bool isNamedLambda() const {
return isLambda() && displayAtom() && !hasInferredName() &&
!hasGuessedAtom();
}
bool hasLexicalThis() const { return isArrow(); }
bool isBuiltinFunctionConstructor();
bool needsPrototypeProperty();
bool strict() const {
MOZ_ASSERT(isInterpreted());
return isInterpretedLazy() ? lazyScript()->strict()
: nonLazyScript()->strict();
}
void setFlags(uint16_t flags) { this->flags_ = flags; }
void setKind(FunctionKind kind) {
this->flags_ &= ~FUNCTION_KIND_MASK;
this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
}
void setIsConstructor() {
MOZ_ASSERT(!isConstructor());
MOZ_ASSERT(isSelfHostedBuiltin());
flags_ |= CONSTRUCTOR;
}
void setIsClassConstructor() {
MOZ_ASSERT(!isClassConstructor());
MOZ_ASSERT(isConstructor());
setKind(ClassConstructor);
}
void clearIsSelfHosted() { flags_ &= ~SELF_HOSTED; }
void setArgCount(uint16_t nargs) { this->nargs_ = nargs; }
void setIsBoundFunction() {
MOZ_ASSERT(!isBoundFunction());
flags_ |= BOUND_FUN;
}
void setIsSelfHostedBuiltin() {
MOZ_ASSERT(isInterpreted());
MOZ_ASSERT(!isSelfHostedBuiltin());
flags_ |= SELF_HOSTED;
flags_ &= ~CONSTRUCTOR;
}
void setIsIntrinsic() {
MOZ_ASSERT(isNative());
MOZ_ASSERT(!isIntrinsic());
flags_ |= SELF_HOSTED;
}
void setArrow() { setKind(Arrow); }
void setResolvedLength() { flags_ |= RESOLVED_LENGTH; }
void setResolvedName() { flags_ |= RESOLVED_NAME; }
bool wasNewScriptCleared() const { return flags_ & NEW_SCRIPT_CLEARED; }
void setNewScriptCleared() { flags_ |= NEW_SCRIPT_CLEARED; }
static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
js::MutableHandleValue v);
JSAtom* infallibleGetUnresolvedName(JSContext* cx);
static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun,
js::MutableHandleString v);
static JSLinearString* getBoundFunctionName(JSContext* cx,
js::HandleFunction fun);
JSAtom* explicitName() const {
return (hasInferredName() || hasGuessedAtom()) ? nullptr : atom_.get();
}
JSAtom* explicitOrInferredName() const {
return hasGuessedAtom() ? nullptr : atom_.get();
}
void initAtom(JSAtom* atom) {
MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
atom_.init(atom);
}
void setAtom(JSAtom* atom) {
MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
atom_ = atom;
}
JSAtom* displayAtom() const { return atom_; }
void setInferredName(JSAtom* atom) {
MOZ_ASSERT(!atom_);
MOZ_ASSERT(atom);
MOZ_ASSERT(!hasGuessedAtom());
setAtom(atom);
flags_ |= HAS_INFERRED_NAME;
}
void clearInferredName() {
MOZ_ASSERT(hasInferredName());
MOZ_ASSERT(atom_);
setAtom(nullptr);
flags_ &= ~HAS_INFERRED_NAME;
}
JSAtom* inferredName() const {
MOZ_ASSERT(hasInferredName());
MOZ_ASSERT(atom_);
return atom_;
}
void setGuessedAtom(JSAtom* atom) {
MOZ_ASSERT(!atom_);
MOZ_ASSERT(atom);
MOZ_ASSERT(!hasInferredName());
MOZ_ASSERT(!hasGuessedAtom());
MOZ_ASSERT(!isBoundFunction());
setAtom(atom);
flags_ |= HAS_GUESSED_ATOM;
}
void clearGuessedAtom() {
MOZ_ASSERT(hasGuessedAtom());
MOZ_ASSERT(!isBoundFunction());
MOZ_ASSERT(atom_);
setAtom(nullptr);
flags_ &= ~HAS_GUESSED_ATOM;
}
void setPrefixedBoundFunctionName(JSAtom* atom) {
MOZ_ASSERT(!hasBoundFunctionNamePrefix());
MOZ_ASSERT(atom);
flags_ |= HAS_BOUND_FUNCTION_NAME_PREFIX;
setAtom(atom);
}
enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
JSObject* environment() const {
MOZ_ASSERT(isInterpreted());
return u.scripted.env_;
}
void setEnvironment(JSObject* obj) {
MOZ_ASSERT(isInterpreted());
*reinterpret_cast<js::GCPtrObject*>(&u.scripted.env_) = obj;
}
void initEnvironment(JSObject* obj) {
MOZ_ASSERT(isInterpreted());
reinterpret_cast<js::GCPtrObject*>(&u.scripted.env_)->init(obj);
}
void unsetEnvironment() { setEnvironment(nullptr); }
public:
static constexpr size_t offsetOfNargs() {
return offsetof(JSFunction, nargs_);
}
static constexpr size_t offsetOfFlags() {
return offsetof(JSFunction, flags_);
}
static size_t offsetOfEnvironment() {
return offsetof(JSFunction, u.scripted.env_);
}
static size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
static bool createScriptForLazilyInterpretedFunction(JSContext* cx,
js::HandleFunction fun);
void maybeRelazify(JSRuntime* rt);
static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) {
MOZ_ASSERT(fun->isInterpreted());
MOZ_ASSERT(cx);
if (fun->isInterpretedLazy()) {
if (!createScriptForLazilyInterpretedFunction(cx, fun)) {
return nullptr;
}
return fun->nonLazyScript();
}
return fun->nonLazyScript();
}
JSScript* existingScriptNonDelazifying() const {
MOZ_ASSERT(isInterpreted());
if (isInterpretedLazy()) {
js::LazyScript* lazy = lazyScript();
JSFunction* fun = lazy->functionNonDelazifying();
MOZ_ASSERT(fun);
return fun->nonLazyScript();
}
return nonLazyScript();
}
JSScript* existingScript() {
MOZ_ASSERT(isInterpreted());
if (isInterpretedLazy()) {
if (shadowZone()->needsIncrementalBarrier()) {
js::LazyScript::writeBarrierPre(lazyScript());
}
JSScript* script = existingScriptNonDelazifying();
flags_ &= ~INTERPRETED_LAZY;
flags_ |= INTERPRETED;
initScript(script);
}
return nonLazyScript();
}
JSFunction* maybeCanonicalFunction() const {
if (hasScript()) {
return nonLazyScript()->functionNonDelazifying();
}
if (isInterpretedLazy() && !isSelfHostedBuiltin()) {
return lazyScript()->functionNonDelazifying();
}
return nullptr;
}
bool hasUncompletedScript() const {
MOZ_ASSERT(hasScript());
return !u.scripted.s.script_;
}
JSScript* nonLazyScript() const {
MOZ_ASSERT(!hasUncompletedScript());
return u.scripted.s.script_;
}
static bool getLength(JSContext* cx, js::HandleFunction fun,
uint16_t* length);
js::LazyScript* lazyScript() const {
MOZ_ASSERT(isInterpretedLazy() && u.scripted.s.lazy_);
return u.scripted.s.lazy_;
}
js::LazyScript* lazyScriptOrNull() const {
MOZ_ASSERT(isInterpretedLazy());
return u.scripted.s.lazy_;
}
js::GeneratorKind generatorKind() const {
if (!isInterpreted()) {
return js::GeneratorKind::NotGenerator;
}
if (hasScript()) {
return nonLazyScript()->generatorKind();
}
if (js::LazyScript* lazy = lazyScriptOrNull()) {
return lazy->generatorKind();
}
MOZ_ASSERT(isSelfHostedBuiltin());
return js::GeneratorKind::NotGenerator;
}
bool isGenerator() const {
return generatorKind() == js::GeneratorKind::Generator;
}
js::FunctionAsyncKind asyncKind() const {
if (!isInterpreted()) {
return js::FunctionAsyncKind::SyncFunction;
}
if (hasScript()) {
return nonLazyScript()->asyncKind();
}
if (js::LazyScript* lazy = lazyScriptOrNull()) {
return lazy->asyncKind();
}
MOZ_ASSERT(isSelfHostedBuiltin());
return js::FunctionAsyncKind::SyncFunction;
}
bool isAsync() const {
return asyncKind() == js::FunctionAsyncKind::AsyncFunction;
}
void setScript(JSScript* script) {
MOZ_ASSERT(realm() == script->realm());
mutableScript() = script;
}
void initScript(JSScript* script) {
MOZ_ASSERT_IF(script, realm() == script->realm());
mutableScript().init(script);
}
void setUnlazifiedScript(JSScript* script) {
MOZ_ASSERT(isInterpretedLazy());
if (lazyScriptOrNull()) {
js::LazyScript::writeBarrierPre(lazyScriptOrNull());
if (!lazyScript()->maybeScript()) {
lazyScript()->initScript(script);
}
}
flags_ &= ~INTERPRETED_LAZY;
flags_ |= INTERPRETED;
initScript(script);
}
void initLazyScript(js::LazyScript* lazy) {
MOZ_ASSERT(isInterpreted());
flags_ &= ~INTERPRETED;
flags_ |= INTERPRETED_LAZY;
u.scripted.s.lazy_ = lazy;
}
JSNative native() const {
MOZ_ASSERT(isNative());
return u.native.func_;
}
JSNative maybeNative() const { return isInterpreted() ? nullptr : native(); }
void initNative(js::Native native, const JSJitInfo* jitInfo) {
MOZ_ASSERT(isNativeWithCppEntry());
MOZ_ASSERT_IF(jitInfo, isBuiltinNative());
MOZ_ASSERT(native);
u.native.func_ = native;
u.native.extra.jitInfo_ = jitInfo;
}
bool hasJitInfo() const {
return isBuiltinNative() && u.native.extra.jitInfo_;
}
const JSJitInfo* jitInfo() const {
MOZ_ASSERT(hasJitInfo());
return u.native.extra.jitInfo_;
}
void setJitInfo(const JSJitInfo* data) {
MOZ_ASSERT(isBuiltinNative());
u.native.extra.jitInfo_ = data;
}
void initWasmNative(js::Native native) {
MOZ_ASSERT(isNativeWithJitEntry());
MOZ_ASSERT(native);
u.native.func_ = native;
u.native.extra.wasmJitEntry_ = nullptr;
}
void setWasmJitEntry(void** entry) {
MOZ_ASSERT(isNativeWithJitEntry());
MOZ_ASSERT(entry);
MOZ_ASSERT(!u.native.extra.wasmJitEntry_);
u.native.extra.wasmJitEntry_ = entry;
}
void** wasmJitEntry() const {
MOZ_ASSERT(isNativeWithJitEntry());
MOZ_ASSERT(u.native.extra.wasmJitEntry_);
return u.native.extra.wasmJitEntry_;
}
void setAsmJSIndex(uint32_t funcIndex) {
MOZ_ASSERT(isAsmJSNative());
MOZ_ASSERT(!isWasmOptimized());
MOZ_ASSERT(!u.native.extra.asmJSFuncIndex_);
u.native.extra.asmJSFuncIndex_ = funcIndex;
}
uint32_t asmJSFuncIndex() const {
MOZ_ASSERT(isAsmJSNative());
MOZ_ASSERT(!isWasmOptimized());
return u.native.extra.asmJSFuncIndex_;
}
bool isDerivedClassConstructor();
static unsigned offsetOfNative() {
return offsetof(JSFunction, u.native.func_);
}
static unsigned offsetOfScript() {
static_assert(offsetof(U, scripted.s.script_) ==
offsetof(U, native.extra.wasmJitEntry_),
"scripted.s.script_ must be at the same offset as "
"native.extra.wasmJitEntry_");
return offsetof(JSFunction, u.scripted.s.script_);
}
static unsigned offsetOfNativeOrEnv() {
static_assert(
offsetof(U, native.func_) == offsetof(U, scripted.env_),
"U.native.func_ must be at the same offset as U.scripted.env_");
return offsetOfNative();
}
static unsigned offsetOfScriptOrLazyScript() {
static_assert(
offsetof(U, scripted.s.script_) == offsetof(U, scripted.s.lazy_),
"U.scripted.s.script_ must be at the same offset as lazy_");
return offsetof(JSFunction, u.scripted.s.script_);
}
static unsigned offsetOfJitInfo() {
return offsetof(JSFunction, u.native.extra.jitInfo_);
}
inline void trace(JSTracer* trc);
JSObject* getBoundFunctionTarget() const;
const js::Value& getBoundFunctionThis() const;
const js::Value& getBoundFunctionArgument(unsigned which) const;
size_t getBoundFunctionArgumentCount() const;
static bool finishBoundFunctionInit(JSContext* cx, js::HandleFunction bound,
js::HandleObject targetObj,
int32_t argCount);
private:
js::GCPtrScript& mutableScript() {
MOZ_ASSERT(hasScript());
return *(js::GCPtrScript*)&u.scripted.s.script_;
}
inline js::FunctionExtended* toExtended();
inline const js::FunctionExtended* toExtended() const;
public:
inline bool isExtended() const {
bool extended = !!(flags() & EXTENDED);
MOZ_ASSERT_IF(isTenured(),
extended == (asTenured().getAllocKind() ==
js::gc::AllocKind::FUNCTION_EXTENDED));
return extended;
}
inline void initializeExtended();
inline void initExtendedSlot(size_t which, const js::Value& val);
inline void setExtendedSlot(size_t which, const js::Value& val);
inline const js::Value& getExtendedSlot(size_t which) const;
static bool setTypeForScriptedFunction(JSContext* cx, js::HandleFunction fun,
bool singleton = false);
js::gc::AllocKind getAllocKind() const {
static_assert(
js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
"extended/non-extended AllocKinds have to be different "
"for getAllocKind() to have a reason to exist");
js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
if (isExtended()) {
kind = js::gc::AllocKind::FUNCTION_EXTENDED;
}
MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
return kind;
}
};
static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
"shadow interface must match actual interface");
extern JSString* fun_toStringHelper(JSContext* cx, js::HandleObject obj,
bool isToSource);
namespace js {
extern bool Function(JSContext* cx, unsigned argc, Value* vp);
extern bool Generator(JSContext* cx, unsigned argc, Value* vp);
extern bool AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
extern bool AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
extern JSFunction* NewFunctionWithProto(
JSContext* cx, JSNative native, unsigned nargs, JSFunction::Flags flags,
HandleObject enclosingEnv, HandleAtom atom, HandleObject proto,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
NewObjectKind newKind = GenericObject);
inline JSFunction* NewNativeFunction(
JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
NewObjectKind newKind = SingletonObject,
JSFunction::Flags flags = JSFunction::NATIVE_FUN) {
MOZ_ASSERT(native);
return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr,
allocKind, newKind);
}
inline JSFunction* NewNativeConstructor(
JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
NewObjectKind newKind = SingletonObject,
JSFunction::Flags flags = JSFunction::NATIVE_CTOR) {
MOZ_ASSERT(native);
MOZ_ASSERT(flags & JSFunction::NATIVE_CTOR);
return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr,
allocKind, newKind);
}
extern JSFunction* NewScriptedFunction(
JSContext* cx, unsigned nargs, JSFunction::Flags flags, HandleAtom atom,
HandleObject proto = nullptr,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
NewObjectKind newKind = GenericObject, HandleObject enclosingEnv = nullptr);
extern bool GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind,
js::FunctionAsyncKind asyncKind,
js::MutableHandleObject proto);
extern JSAtom* IdToFunctionName(
JSContext* cx, HandleId id,
FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
extern bool SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name,
FunctionPrefixKind prefixKind);
extern JSFunction* DefineFunction(
JSContext* cx, HandleObject obj, HandleId id, JSNative native,
unsigned nargs, unsigned flags,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
extern bool fun_toString(JSContext* cx, unsigned argc, Value* vp);
struct WellKnownSymbols;
extern bool FunctionHasDefaultHasInstance(JSFunction* fun,
const WellKnownSymbols& symbols);
extern void ThrowTypeErrorBehavior(JSContext* cx);
class FunctionExtended : public JSFunction {
public:
static const unsigned NUM_EXTENDED_SLOTS = 2;
static const unsigned ARROW_NEWTARGET_SLOT = 0;
static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
static const unsigned WASM_INSTANCE_SLOT = 0;
static const unsigned WASM_TLSDATA_SLOT = 1;
static const unsigned ASMJS_MODULE_SLOT = 0;
static inline size_t offsetOfExtendedSlot(unsigned which) {
MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
return offsetof(FunctionExtended, extendedSlots) +
which * sizeof(GCPtrValue);
}
static inline size_t offsetOfArrowNewTargetSlot() {
return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
}
static inline size_t offsetOfMethodHomeObjectSlot() {
return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT);
}
private:
friend class JSFunction;
GCPtrValue extendedSlots[NUM_EXTENDED_SLOTS];
};
extern bool CanReuseScriptForClone(JS::Realm* realm, HandleFunction fun,
HandleObject newParent);
extern JSFunction* CloneFunctionReuseScript(
JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind kind = gc::AllocKind::FUNCTION,
NewObjectKind newKindArg = GenericObject, HandleObject proto = nullptr);
extern JSFunction* CloneFunctionAndScript(
JSContext* cx, HandleFunction fun, HandleObject parent,
HandleScope newScope, Handle<ScriptSourceObject*> sourceObject,
gc::AllocKind kind = gc::AllocKind::FUNCTION, HandleObject proto = nullptr);
extern JSFunction* CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun);
extern JSFunction* CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun);
}
inline js::FunctionExtended* JSFunction::toExtended() {
MOZ_ASSERT(isExtended());
return static_cast<js::FunctionExtended*>(this);
}
inline const js::FunctionExtended* JSFunction::toExtended() const {
MOZ_ASSERT(isExtended());
return static_cast<const js::FunctionExtended*>(this);
}
inline void JSFunction::initializeExtended() {
MOZ_ASSERT(isExtended());
MOZ_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
toExtended()->extendedSlots[0].init(js::UndefinedValue());
toExtended()->extendedSlots[1].init(js::UndefinedValue());
}
inline void JSFunction::initExtendedSlot(size_t which, const js::Value& val) {
MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
toExtended()->extendedSlots[which].init(val);
}
inline void JSFunction::setExtendedSlot(size_t which, const js::Value& val) {
MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
toExtended()->extendedSlots[which] = val;
}
inline const js::Value& JSFunction::getExtendedSlot(size_t which) const {
MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
return toExtended()->extendedSlots[which];
}
namespace js {
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource);
template <XDRMode mode>
XDRResult XDRInterpretedFunction(XDRState<mode>* xdr,
HandleScope enclosingScope,
HandleScriptSourceObject sourceObject,
MutableHandleFunction objp);
extern void ReportIncompatibleMethod(JSContext* cx, const CallArgs& args,
const Class* clasp);
extern void ReportIncompatible(JSContext* cx, const CallArgs& args);
extern bool fun_apply(JSContext* cx, unsigned argc, Value* vp);
extern bool fun_call(JSContext* cx, unsigned argc, Value* vp);
}
#ifdef DEBUG
namespace JS {
namespace detail {
JS_PUBLIC_API void CheckIsValidConstructible(const Value& calleev);
} } #endif
#endif