https://github.com/mozilla/gecko-dev
Tip revision: 922e3076b91eda3e2d1be3e61c734b38aa3b3ceb authored by Jeff Walden on 15 March 2014, 08:11:57 UTC
Bug 982974 - Be paranoid when neutering ArrayBuffers. r=sfink, a=1.1.x+
Bug 982974 - Be paranoid when neutering ArrayBuffers. r=sfink, a=1.1.x+
Tip revision: 922e307
jsfun.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jsfun_h___
#define jsfun_h___
/*
* JS function definitions.
*/
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsobj.h"
#include "jsatom.h"
#include "jsscript.h"
#include "jsstr.h"
#include "gc/Barrier.h"
/*
* The high two bits of JSFunction.flags encode whether the function is native
* or interpreted, and if interpreted, what kind of optimized closure form (if
* any) it might be.
*
* 00 not interpreted
* 01 interpreted, not null closure
* 11 interpreted, null closure
*
* NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
* bit only, never stored in fun->flags.
*
* If we need more bits in the future, all flags for interpreted functions can
* move to u.i.script->flags. For now we use function flag bits to minimize
* pointer-chasing.
*/
#define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some
global object */
#define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
#define JSFUN_EXTENDED 0x2000 /* structure is FunctionExtended */
/*
* NB: JSFUN_INTERPRETED is hardcode duplicated in SET_JITINFO() in
* jsfriendapi.h. If it changes, it must also be updated there.
*/
#define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.native */
#define JSFUN_HAS_GUESSED_ATOM 0x8000 /* function had no explicit name, but a
name was guessed for it anyway */
namespace js { class FunctionExtended; }
struct JSFunction : public JSObject
{
uint16_t nargs; /* maximum number of specified arguments,
reflected as f.length/f.arity */
uint16_t flags; /* flags, see JSFUN_* below and in jsapi.h */
union U {
class Native {
friend struct JSFunction;
js::Native native; /* native method pointer or null */
const JSJitInfo *jitinfo; /* Information about this function to be
used by the JIT;
use the accessor! */
} n;
struct Scripted {
JSScript *script_; /* interpreted bytecode descriptor or null;
use the accessor! */
JSObject *env_; /* environment for new activations;
use the accessor! */
} i;
void *nativeOrScript;
} u;
private:
js::HeapPtrAtom atom_; /* name for diagnostics and decompiling */
public:
bool hasDefaults() const { return flags & JSFUN_HAS_DEFAULTS; }
bool hasRest() const { return flags & JSFUN_HAS_REST; }
bool hasGuessedAtom() const { return flags & JSFUN_HAS_GUESSED_ATOM; }
bool isInterpreted() const { return flags & JSFUN_INTERPRETED; }
bool isNative() const { return !isInterpreted(); }
bool isSelfHostedBuiltin() const { return flags & JSFUN_SELF_HOSTED; }
bool isBuiltin() const { return isNative() || isSelfHostedBuiltin(); }
bool isSelfHostedConstructor() const { return flags & JSFUN_SELF_HOSTED_CTOR; }
bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
bool isInterpretedConstructor() const {
return isInterpreted() && !isFunctionPrototype() &&
(!isSelfHostedBuiltin() || isSelfHostedConstructor());
}
bool isNamedLambda() const {
return (flags & JSFUN_LAMBDA) && atom_ && !hasGuessedAtom();
}
/* Returns the strictness of this function, which must be interpreted. */
inline bool inStrictMode() const;
void setArgCount(uint16_t nargs) {
JS_ASSERT(this->nargs == 0);
this->nargs = nargs;
}
void setHasRest() {
JS_ASSERT(!hasRest());
this->flags |= JSFUN_HAS_REST;
}
void setHasDefaults() {
JS_ASSERT(!hasDefaults());
this->flags |= JSFUN_HAS_DEFAULTS;
}
JSAtom *atom() const { return hasGuessedAtom() ? NULL : atom_.get(); }
inline void initAtom(JSAtom *atom);
JSAtom *displayAtom() const { return atom_; }
inline void setGuessedAtom(JSAtom *atom);
/* uint16_t representation bounds number of call object dynamic slots. */
enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
/*
* For an interpreted function, accessors for the initial scope object of
* activations (stack frames) of the function.
*/
inline JSObject *environment() const;
inline void setEnvironment(JSObject *obj);
inline void initEnvironment(JSObject *obj);
static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
JS::HandleScript script() const {
JS_ASSERT(isInterpreted());
return JS::HandleScript::fromMarkedLocation(&u.i.script_);
}
js::HeapPtrScript &mutableScript() {
JS_ASSERT(isInterpreted());
return *(js::HeapPtrScript *)&u.i.script_;
}
inline void setScript(JSScript *script_);
inline void initScript(JSScript *script_);
JS::HandleScript maybeScript() const {
return isInterpreted() ? script() : JS::NullPtr();
}
JSNative native() const {
JS_ASSERT(isNative());
return u.n.native;
}
JSNative maybeNative() const {
return isInterpreted() ? NULL : native();
}
inline void initNative(js::Native native, const JSJitInfo *jitinfo);
inline const JSJitInfo *jitInfo() const;
inline void setJitInfo(const JSJitInfo *data);
static unsigned offsetOfNativeOrScript() {
JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.script_));
JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript));
return offsetof(JSFunction, u.nativeOrScript);
}
#if JS_BITS_PER_WORD == 32
static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2_BACKGROUND;
static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
#else
static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8_BACKGROUND;
#endif
inline void trace(JSTracer *trc);
/* Bound function accessors. */
inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg,
const js::Value *args, unsigned argslen);
inline JSObject *getBoundFunctionTarget() const;
inline const js::Value &getBoundFunctionThis() const;
inline const js::Value &getBoundFunctionArgument(unsigned which) const;
inline size_t getBoundFunctionArgumentCount() const;
private:
inline js::FunctionExtended *toExtended();
inline const js::FunctionExtended *toExtended() const;
inline bool isExtended() const {
JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
JS_ASSERT(!!(flags & JSFUN_EXTENDED) == (getAllocKind() == ExtendedFinalizeKind));
return !!(flags & JSFUN_EXTENDED);
}
public:
/* Accessors for data stored in extended functions. */
inline void initializeExtended();
inline void setExtendedSlot(size_t which, const js::Value &val);
inline const js::Value &getExtendedSlot(size_t which) const;
/* Constructs a new type for the function if necessary. */
static bool setTypeForScriptedFunction(JSContext *cx, js::HandleFunction fun,
bool singleton = false);
private:
static void staticAsserts() {
MOZ_STATIC_ASSERT(sizeof(JSFunction) == sizeof(js::shadow::Function),
"shadow interface must match actual interface");
}
/*
* These member functions are inherited from JSObject, but should never be applied to
* a value statically known to be a JSFunction.
*/
inline JSFunction *toFunction() MOZ_DELETE;
inline const JSFunction *toFunction() const MOZ_DELETE;
};
inline JSFunction *
JSObject::toFunction()
{
JS_ASSERT(JS_ObjectIsFunction(NULL, this));
return static_cast<JSFunction *>(this);
}
inline const JSFunction *
JSObject::toFunction() const
{
JS_ASSERT(JS_ObjectIsFunction(NULL, const_cast<JSObject *>(this)));
return static_cast<const JSFunction *>(this);
}
extern JSString *
fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent);
extern JSFunction *
js_NewFunction(JSContext *cx, js::HandleObject funobj, JSNative native, unsigned nargs,
unsigned flags, js::HandleObject parent, js::HandleAtom atom,
js::gc::AllocKind kind = JSFunction::FinalizeKind);
extern JSFunction * JS_FASTCALL
js_CloneFunctionObject(JSContext *cx, js::HandleFunction fun,
js::HandleObject parent, js::HandleObject proto,
js::gc::AllocKind kind = JSFunction::FinalizeKind);
extern JSFunction *
js_DefineFunction(JSContext *cx, js::HandleObject obj, js::HandleId id, JSNative native,
unsigned nargs, unsigned flags, const char *selfHostedName = NULL,
js::gc::AllocKind kind = JSFunction::FinalizeKind);
namespace js {
/*
* Function extended with reserved slots for use by various kinds of functions.
* Most functions do not have these extensions, but enough are that efficient
* storage is required (no malloc'ed reserved slots).
*/
class FunctionExtended : public JSFunction
{
friend struct JSFunction;
/* Reserved slots available for storage by particular native functions. */
HeapValue extendedSlots[2];
};
} // namespace js
inline js::FunctionExtended *
JSFunction::toExtended()
{
JS_ASSERT(isExtended());
return static_cast<js::FunctionExtended *>(this);
}
inline const js::FunctionExtended *
JSFunction::toExtended() const
{
JS_ASSERT(isExtended());
return static_cast<const js::FunctionExtended *>(this);
}
namespace js {
JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen);
template<XDRMode mode>
bool
XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope,
HandleScript enclosingScript, MutableHandleObject objp);
extern JSObject *
CloneInterpretedFunction(JSContext *cx, HandleObject enclosingScope, HandleFunction fun);
/*
* Report an error that call.thisv is not compatible with the specified class,
* assuming that the method (clasp->name).prototype.<name of callee function>
* is what was called.
*/
extern void
ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
/*
* Report an error that call.thisv is not an acceptable this for the callee
* function.
*/
extern void
ReportIncompatible(JSContext *cx, CallReceiver call);
} /* namespace js */
extern JSBool
js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
extern JSBool
js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
extern JSObject*
js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg,
js::Value *boundArgs, unsigned argslen);
#endif /* jsfun_h___ */