mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 773850 - Refactor method guarding to be able to work for methods that must be able to accept a |this| which is a proxy. r=luke
--HG-- extra : rebase_source : 1a015ffd3faa9fa6c82426c94058bce026602f8c
This commit is contained in:
parent
1f7d331861
commit
1cf3018b6e
@ -104,9 +104,13 @@ static const uint32_t XBLPROTO_SLOT = 0;
|
||||
static const uint32_t FIELD_SLOT = 1;
|
||||
|
||||
static bool
|
||||
ObjectHasISupportsPrivate(JS::Handle<JSObject*> obj)
|
||||
ValueHasISupportsPrivate(const JS::Value &v)
|
||||
{
|
||||
JSClass* clasp = ::JS_GetClass(obj);
|
||||
if (!v.isObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSClass* clasp = ::JS_GetClass(&v.toObject());
|
||||
const uint32_t HAS_PRIVATE_NSISUPPORTS =
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
|
||||
return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS;
|
||||
@ -127,7 +131,7 @@ InstallXBLField(JSContext* cx,
|
||||
//
|
||||
// FieldAccessorGuard already determined whether |thisObj| was acceptable as
|
||||
// |this| in terms of not throwing a TypeError. Assert this for good measure.
|
||||
MOZ_ASSERT(ObjectHasISupportsPrivate(thisObj));
|
||||
MOZ_ASSERT(ValueHasISupportsPrivate(JS::ObjectValue(*thisObj)));
|
||||
|
||||
// But there are some cases where we must accept |thisObj| but not install a
|
||||
// property on it, or otherwise touch it. Hence this split of |this|-vetting
|
||||
@ -210,91 +214,23 @@ InstallXBLField(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine whether the |this| passed to this method is valid for an XBL field
|
||||
// access (which is to say, an object with an nsISupports private), taking into
|
||||
// account proxies and/or wrappers around |this|. There are three possible
|
||||
// outcomes from calling this method:
|
||||
//
|
||||
// 1. An error was hit, and this method returned false. In this case, the
|
||||
// caller should propagate it.
|
||||
// 2. The |this| passed in was directly acceptable for XBL field access. This
|
||||
// method returned true and set *thisObj to a |this| that can be used for
|
||||
// field definition (i.e. that passes ObjectHasISupportsPrivate). In this
|
||||
// case, the caller should install the field on *thisObj.
|
||||
// 3. The |this| passed in was a proxy/wrapper around an object usable for
|
||||
// XBL field access. The method recursively (and successfully) invoked the
|
||||
// native on the unwrapped |this|, then it returned true and set *thisObj
|
||||
// to null. In this case, the caller should itself return true.
|
||||
//
|
||||
// Thus this method implements the JS_CallNonGenericMethodOnProxy idiom in
|
||||
// jsapi.h.
|
||||
//
|
||||
// Note that a |this| valid for field access is *not* necessarily one on which
|
||||
// the field value will be installed. It's just one where calling the specified
|
||||
// method on it won't unconditionally throw a TypeError. Confusing? Perhaps,
|
||||
// but it's compatible with what we did before we implemented XBL fields using
|
||||
// this technique.
|
||||
inline bool
|
||||
FieldAccessorGuard(JSContext *cx, unsigned argc, JS::Value *vp, JSNative native, JSObject **thisObj)
|
||||
static bool
|
||||
FieldGetterImpl(JSContext *cx, JS::CallArgs args)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
|
||||
if (!obj) {
|
||||
xpc::Throw(cx, NS_ERROR_UNEXPECTED);
|
||||
return false;
|
||||
}
|
||||
const JS::Value &thisv = args.thisv();
|
||||
MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
|
||||
|
||||
if (ObjectHasISupportsPrivate(obj)) {
|
||||
*thisObj = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
// |this| wasn't an unwrapped object passing the has-private-nsISupports test.
|
||||
// So try to unwrap |this| and recursively call the native on it.
|
||||
//
|
||||
// This |protoClass| gunk is needed for the JS engine to report an error if an
|
||||
// object of the wrong class was passed as |this|, so that it can complain
|
||||
// that it expected an object of type |protoClass|. It would be better if the
|
||||
// error didn't try to specify the expected class of objects -- particularly
|
||||
// because there's no one class of objects -- but it's what the API wants, so
|
||||
// pass a class that's marginally correct as an answer.
|
||||
JSClass* protoClass;
|
||||
{
|
||||
JS::Rooted<JSObject*> callee(cx, &JS_CALLEE(cx, vp).toObject());
|
||||
JS::Rooted<JSObject*> xblProto(cx);
|
||||
xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, xblProto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protoClass = ::JS_GetClass(xblProto);
|
||||
}
|
||||
|
||||
*thisObj = NULL;
|
||||
return JS_CallNonGenericMethodOnProxy(cx, argc, vp, native, protoClass);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
FieldGetter(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> thisObj(cx);
|
||||
if (!FieldAccessorGuard(cx, argc, vp, FieldGetter, thisObj.address())) {
|
||||
return false;
|
||||
}
|
||||
if (!thisObj) {
|
||||
return true; // FieldGetter was recursively invoked on an unwrapped |this|
|
||||
}
|
||||
JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
|
||||
|
||||
bool installed = false;
|
||||
JS::Rooted<JSObject*> callee(cx, &JS_CALLEE(cx, vp).toObject());
|
||||
JS::Rooted<JSObject*> callee(cx, &args.calleev().toObject());
|
||||
JS::Rooted<jsid> id(cx);
|
||||
if (!InstallXBLField(cx, callee, thisObj, id.address(), &installed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!installed) {
|
||||
JS_SET_RVAL(cx, vp, JS::UndefinedValue());
|
||||
args.rval() = JS::UndefinedValue();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -302,33 +238,46 @@ FieldGetter(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
if (!JS_GetPropertyById(cx, thisObj, id, v.address())) {
|
||||
return false;
|
||||
}
|
||||
JS_SET_RVAL(cx, vp, v);
|
||||
args.rval() = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
FieldSetter(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
FieldGetter(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> thisObj(cx);
|
||||
if (!FieldAccessorGuard(cx, argc, vp, FieldSetter, thisObj.address())) {
|
||||
return false;
|
||||
}
|
||||
if (!thisObj) {
|
||||
return true; // FieldSetter was recursively invoked on an unwrapped |this|
|
||||
}
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
return JS::CallNonGenericMethod(cx, ValueHasISupportsPrivate, FieldGetterImpl,
|
||||
args);
|
||||
}
|
||||
|
||||
static bool
|
||||
FieldSetterImpl(JSContext *cx, JS::CallArgs args)
|
||||
{
|
||||
const JS::Value &thisv = args.thisv();
|
||||
MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
|
||||
|
||||
JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
|
||||
|
||||
bool installed = false;
|
||||
JS::Rooted<JSObject*> callee(cx, &JS_CALLEE(cx, vp).toObject());
|
||||
JS::Rooted<JSObject*> callee(cx, &args.calleev().toObject());
|
||||
JS::Rooted<jsid> id(cx);
|
||||
if (!InstallXBLField(cx, callee, thisObj, id.address(), &installed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> v(cx,
|
||||
argc > 0 ? JS_ARGV(cx, vp)[0] : JS::UndefinedValue());
|
||||
args.length() > 0 ? args[0] : JS::UndefinedValue());
|
||||
return JS_SetPropertyById(cx, thisObj, id, v.address());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
FieldSetter(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
return JS::CallNonGenericMethod(cx, ValueHasISupportsPrivate, FieldSetterImpl,
|
||||
args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
XBLResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
|
||||
JSMutableHandleObject objp)
|
||||
|
@ -115,7 +115,6 @@ CPPSRCS = \
|
||||
ScopeObject.cpp \
|
||||
Debugger.cpp \
|
||||
GlobalObject.cpp \
|
||||
MethodGuard.cpp \
|
||||
ObjectImpl.cpp \
|
||||
Stack.cpp \
|
||||
String.cpp \
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/Stack.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
@ -227,42 +226,49 @@ MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
#define UNPACK_THIS(T, native, cx, argc, vp, args, data) \
|
||||
CallArgs args = CallArgsFromVp(argc, vp); \
|
||||
if (!args.thisv().isObject() || \
|
||||
!args.thisv().toObject().hasClass(&T::class_)) \
|
||||
{ \
|
||||
return js::HandleNonGenericMethodClassMismatch(cx, args, native, \
|
||||
&T::class_); \
|
||||
} \
|
||||
if (!args.thisv().toObject().getPrivate()) { \
|
||||
ReportIncompatibleMethod(cx, args, &T::class_); \
|
||||
return false; \
|
||||
} \
|
||||
T::Data &data = *static_cast<T &>(args.thisv().toObject()).getData(); \
|
||||
(void) data
|
||||
|
||||
#define THIS_MAP(native, cx, argc, vp, args, map) \
|
||||
UNPACK_THIS(MapObject, native, cx, argc, vp, args, map)
|
||||
bool
|
||||
MapObject::is(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().getPrivate();
|
||||
}
|
||||
|
||||
#define ARG0_KEY(cx, args, key) \
|
||||
HashableValue key; \
|
||||
if (args.length() > 0 && !key.setValue(cx, args[0])) \
|
||||
return false
|
||||
|
||||
JSBool
|
||||
MapObject::size(JSContext *cx, unsigned argc, Value *vp)
|
||||
ValueMap &
|
||||
MapObject::extract(CallReceiver call)
|
||||
{
|
||||
THIS_MAP(size, cx, argc, vp, args, map);
|
||||
JS_ASSERT(call.thisv().isObject());
|
||||
JS_ASSERT(call.thisv().toObject().hasClass(&MapObject::class_));
|
||||
return *static_cast<MapObject&>(call.thisv().toObject()).getData();
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::size_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(MapObject::is(args.thisv()));
|
||||
|
||||
ValueMap &map = extract(args);
|
||||
JS_STATIC_ASSERT(sizeof map.count() <= sizeof(uint32_t));
|
||||
args.rval().setNumber(map.count());
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::get(JSContext *cx, unsigned argc, Value *vp)
|
||||
MapObject::size(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_MAP(get, cx, argc, vp, args, map);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, size_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::get_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(MapObject::is(args.thisv()));
|
||||
|
||||
ValueMap &map = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
|
||||
if (ValueMap::Ptr p = map.lookup(key))
|
||||
@ -273,18 +279,36 @@ MapObject::get(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::has(JSContext *cx, unsigned argc, Value *vp)
|
||||
MapObject::get(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_MAP(has, cx, argc, vp, args, map);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, get_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::has_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(MapObject::is(args.thisv()));
|
||||
|
||||
ValueMap &map = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
args.rval().setBoolean(map.lookup(key));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::set(JSContext *cx, unsigned argc, Value *vp)
|
||||
MapObject::has(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_MAP(set, cx, argc, vp, args, map);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, has_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::set_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(MapObject::is(args.thisv()));
|
||||
|
||||
ValueMap &map = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
if (!map.put(key, args.length() > 1 ? args[1] : UndefinedValue())) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
@ -295,9 +319,18 @@ MapObject::set(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
||||
MapObject::set(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_MAP(delete_, cx, argc, vp, args, map);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, set_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::delete_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(MapObject::is(args.thisv()));
|
||||
|
||||
ValueMap &map = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
ValueMap::Ptr p = map.lookup(key);
|
||||
bool found = p.found();
|
||||
@ -307,6 +340,13 @@ MapObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, delete_impl, args);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitMapClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
@ -404,31 +444,62 @@ SetObject::construct(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
#define THIS_SET(native, cx, argc, vp, args, set) \
|
||||
UNPACK_THIS(SetObject, native, cx, argc, vp, args, set)
|
||||
|
||||
JSBool
|
||||
SetObject::size(JSContext *cx, unsigned argc, Value *vp)
|
||||
bool
|
||||
SetObject::is(const Value &v)
|
||||
{
|
||||
THIS_SET(size, cx, argc, vp, args, set);
|
||||
return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().getPrivate();
|
||||
}
|
||||
|
||||
ValueSet &
|
||||
SetObject::extract(CallReceiver call)
|
||||
{
|
||||
JS_ASSERT(call.thisv().isObject());
|
||||
JS_ASSERT(call.thisv().toObject().hasClass(&SetObject::class_));
|
||||
return *static_cast<SetObject&>(call.thisv().toObject()).getData();
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::size_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
ValueSet &set = extract(args);
|
||||
JS_STATIC_ASSERT(sizeof set.count() <= sizeof(uint32_t));
|
||||
args.rval().setNumber(set.count());
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetObject::has(JSContext *cx, unsigned argc, Value *vp)
|
||||
SetObject::size(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_SET(has, cx, argc, vp, args, set);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, size_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::has_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
ValueSet &set = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
args.rval().setBoolean(set.has(key));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetObject::add(JSContext *cx, unsigned argc, Value *vp)
|
||||
SetObject::has(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_SET(add, cx, argc, vp, args, set);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, has_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::add_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
ValueSet &set = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
if (!set.put(key)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
@ -439,9 +510,18 @@ SetObject::add(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
||||
SetObject::add(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_SET(delete_, cx, argc, vp, args, set);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, add_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::delete_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
ValueSet &set = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
ValueSet::Ptr p = set.lookup(key);
|
||||
bool found = p.found();
|
||||
@ -451,6 +531,13 @@ SetObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, delete_impl, args);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitSetClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
|
@ -74,16 +74,24 @@ class MapObject : public JSObject {
|
||||
static JSObject *initClass(JSContext *cx, JSObject *obj);
|
||||
static Class class_;
|
||||
private:
|
||||
typedef ValueMap Data;
|
||||
static JSFunctionSpec methods[];
|
||||
ValueMap *getData() { return static_cast<ValueMap *>(getPrivate()); }
|
||||
static ValueMap & extract(CallReceiver call);
|
||||
static void mark(JSTracer *trc, JSObject *obj);
|
||||
static void finalize(FreeOp *fop, JSObject *obj);
|
||||
static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool is(const Value &v);
|
||||
|
||||
static bool size_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool size(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool get_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool get(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool has_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool has(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool set_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool set(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool delete_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
@ -92,15 +100,22 @@ class SetObject : public JSObject {
|
||||
static JSObject *initClass(JSContext *cx, JSObject *obj);
|
||||
static Class class_;
|
||||
private:
|
||||
typedef ValueSet Data;
|
||||
static JSFunctionSpec methods[];
|
||||
ValueSet *getData() { return static_cast<ValueSet *>(getPrivate()); }
|
||||
static ValueSet & extract(CallReceiver call);
|
||||
static void mark(JSTracer *trc, JSObject *obj);
|
||||
static void finalize(FreeOp *fop, JSObject *obj);
|
||||
static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool is(const Value &v);
|
||||
|
||||
static bool size_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool size(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool has_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool has(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool add_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool add(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool delete_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "builtin/RegExp.h"
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
#include "vm/RegExpStatics-inl.h"
|
||||
|
||||
@ -293,19 +292,25 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsRegExp(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&RegExpClass);
|
||||
}
|
||||
|
||||
static bool
|
||||
regexp_compile_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsRegExp(args.thisv()));
|
||||
RegExpObjectBuilder builder(cx, &args.thisv().toObject().asRegExp());
|
||||
return CompileRegExpObject(cx, builder, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
regexp_compile(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, regexp_compile, &RegExpClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
RegExpObjectBuilder builder(cx, &thisObj->asRegExp());
|
||||
return CompileRegExpObject(cx, builder, args);
|
||||
return CallNonGenericMethod(cx, IsRegExp, regexp_compile_impl, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -332,23 +337,24 @@ regexp_construct(JSContext *cx, unsigned argc, Value *vp)
|
||||
return CompileRegExpObject(cx, builder, args);
|
||||
}
|
||||
|
||||
static bool
|
||||
regexp_toString_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsRegExp(args.thisv()));
|
||||
|
||||
JSString *str = args.thisv().toObject().asRegExp().toString(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
args.rval() = StringValue(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
regexp_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, regexp_toString, &RegExpClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JSString *str = thisObj->asRegExp().toString(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
*vp = StringValue(str);
|
||||
return true;
|
||||
return CallNonGenericMethod(cx, IsRegExp, regexp_toString_impl, args);
|
||||
}
|
||||
|
||||
static JSFunctionSpec regexp_methods[] = {
|
||||
@ -541,18 +547,10 @@ GetSharedForGreedyStar(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGu
|
||||
* |execType| to perform this optimization.
|
||||
*/
|
||||
static bool
|
||||
ExecuteRegExp(JSContext *cx, Native native, unsigned argc, Value *vp)
|
||||
ExecuteRegExp(JSContext *cx, RegExpExecType execType, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Step 1. */
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, native, &RegExpClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
Rooted<RegExpObject*> reobj(cx, &thisObj->asRegExp());
|
||||
/* Step 1 was performed by CallNonGenericMethod. */
|
||||
Rooted<RegExpObject*> reobj(cx, &args.thisv().toObject().asRegExp());
|
||||
|
||||
RegExpGuard re;
|
||||
if (StartsWithGreedyStar(reobj->getSource())) {
|
||||
@ -598,7 +596,6 @@ ExecuteRegExp(JSContext *cx, Native native, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
/* Steps 8-21. */
|
||||
RegExpExecType execType = (native == regexp_test) ? RegExpTest : RegExpExec;
|
||||
size_t lastIndexInt(i);
|
||||
if (!ExecuteRegExp(cx, res, *re, linearInput, chars, length, &lastIndexInt, execType,
|
||||
&args.rval())) {
|
||||
@ -617,19 +614,33 @@ ExecuteRegExp(JSContext *cx, Native native, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
/* ES5 15.10.6.2. */
|
||||
static bool
|
||||
regexp_exec_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
return ExecuteRegExp(cx, RegExpExec, args);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js::regexp_exec(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return ExecuteRegExp(cx, regexp_exec, argc, vp);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsRegExp, regexp_exec_impl, args);
|
||||
}
|
||||
|
||||
/* ES5 15.10.6.3. */
|
||||
static bool
|
||||
regexp_test_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
if (!ExecuteRegExp(cx, RegExpTest, args))
|
||||
return false;
|
||||
if (!args.rval().isTrue())
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js::regexp_test(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
if (!ExecuteRegExp(cx, regexp_test, argc, vp))
|
||||
return false;
|
||||
if (!vp->isTrue())
|
||||
vp->setBoolean(false);
|
||||
return true;
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsRegExp, regexp_test_impl, args);
|
||||
}
|
||||
|
@ -20,16 +20,25 @@ static JSClass CustomClass = {
|
||||
|
||||
static const uint32_t CUSTOM_SLOT = 0;
|
||||
|
||||
static bool
|
||||
IsCustomClass(const Value &v)
|
||||
{
|
||||
return v.isObject() && JS_GetClass(&v.toObject()) == &CustomClass;
|
||||
}
|
||||
|
||||
static bool
|
||||
CustomMethodImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsCustomClass(args.thisv()));
|
||||
args.rval() = JS_GetReservedSlot(&args.thisv().toObject(), CUSTOM_SLOT);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
CustomMethod(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
const Value &thisv = JS_THIS_VALUE(cx, vp);
|
||||
JSObject *thisObj;
|
||||
if (!thisv.isObject() || JS_GetClass((thisObj = &thisv.toObject())) != &CustomClass)
|
||||
return JS_CallNonGenericMethodOnProxy(cx, argc, vp, CustomMethod, &CustomClass);
|
||||
|
||||
JS_SET_RVAL(cx, vp, JS_GetReservedSlot(thisObj, CUSTOM_SLOT));
|
||||
return true;
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsCustomClass, CustomMethodImpl, args);
|
||||
}
|
||||
|
||||
BEGIN_TEST(test_CallNonGenericMethodOnProxy)
|
||||
|
@ -61,7 +61,6 @@
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Memory.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "vm/Xdr.h"
|
||||
@ -88,6 +87,24 @@ using namespace js;
|
||||
using namespace js::gc;
|
||||
using namespace js::types;
|
||||
|
||||
bool
|
||||
JS::detail::CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
JS_ASSERT(!test(thisv));
|
||||
|
||||
if (thisv.isObject()) {
|
||||
JSObject &thisObj = args.thisv().toObject();
|
||||
if (thisObj.isProxy())
|
||||
return Proxy::nativeCall(cx, test, impl, args);
|
||||
}
|
||||
|
||||
ReportIncompatible(cx, args);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This class is a version-establishing barrier at the head of a VM entry or
|
||||
* re-entry. It ensures that:
|
||||
@ -4874,14 +4891,6 @@ JS_DefineFunctionById(JSContext *cx, JSObject *obj_, jsid id_, JSNative call,
|
||||
return js_DefineFunction(cx, obj, id, call, nargs, attrs);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native,
|
||||
JSClass *clasp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return HandleNonGenericMethodClassMismatch(cx, args, native, Valueify(clasp));
|
||||
}
|
||||
|
||||
struct AutoLastFrameCheck {
|
||||
AutoLastFrameCheck(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: cx(cx) {
|
||||
|
149
js/src/jsapi.h
149
js/src/jsapi.h
@ -1443,6 +1443,93 @@ CallArgsFromSp(unsigned argc, Value *sp)
|
||||
return CallArgsFromArgv(argc, sp - argc);
|
||||
}
|
||||
|
||||
/* Returns true if |v| is considered an acceptable this-value. */
|
||||
typedef bool (*IsAcceptableThis)(const Value &v);
|
||||
|
||||
/*
|
||||
* Implements the guts of a method; guaranteed to be provided an acceptable
|
||||
* this-value, as determined by a corresponding IsAcceptableThis method.
|
||||
*/
|
||||
typedef bool (*NativeImpl)(JSContext *cx, CallArgs args);
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* DON'T CALL THIS DIRECTLY. It's for use only by CallNonGenericMethod! */
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
/*
|
||||
* Methods usually act upon |this| objects only from a single global object and
|
||||
* compartment. Sometimes, however, a method must act upon |this| values from
|
||||
* multiple global objects or compartments. In such cases the |this| value a
|
||||
* method might see will be wrapped, such that various access to the object --
|
||||
* to its class, its private data, its reserved slots, and so on -- will not
|
||||
* work properly without entering that object's compartment. This method
|
||||
* implements a solution to this problem.
|
||||
*
|
||||
* To implement a method that accepts |this| values from multiple compartments,
|
||||
* define two functions. The first function matches the IsAcceptableThis type
|
||||
* and indicates whether the provided value is an acceptable |this| for the
|
||||
* method; it must be a pure function only of its argument.
|
||||
*
|
||||
* static JSClass AnswerClass = { ... };
|
||||
*
|
||||
* static bool
|
||||
* IsAnswerObject(const Value &v)
|
||||
* {
|
||||
* if (!v.isObject())
|
||||
* return false;
|
||||
* return JS_GetClass(&v.toObject()) == &AnswerClass;
|
||||
* }
|
||||
*
|
||||
* The second function implements the NativeImpl signature and defines the
|
||||
* behavior of the method when it is provided an acceptable |this| value.
|
||||
* Aside from some typing niceties -- see the CallArgs interface for details --
|
||||
* its interface is the same as that of JSNative.
|
||||
*
|
||||
* static bool
|
||||
* answer_getAnswer_impl(JSContext *cx, JS::CallArgs args)
|
||||
* {
|
||||
* args.rval().setInt32(42);
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* The implementation function is guaranteed to be called *only* with a |this|
|
||||
* value which is considered acceptable.
|
||||
*
|
||||
* Now to implement the actual method, write a JSNative that calls the method
|
||||
* declared below, passing the appropriate arguments.
|
||||
*
|
||||
* static JSBool
|
||||
* answer_getAnswer(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
* {
|
||||
* JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
* return JS::CallNonGenericMethod(cx, IsAnswerObject,
|
||||
answer_getAnswer_impl, args);
|
||||
* }
|
||||
*
|
||||
* JS::CallNonGenericMethod will test whether |args.thisv()| is acceptable. If
|
||||
* it is, it will call the provided implementation function, which will return
|
||||
* a value and indicate success. If it is not, it will attempt to unwrap
|
||||
* |this| and call the implementation function on the unwrapped |this|. If
|
||||
* that succeeds, all well and good. If it doesn't succeed, a TypeError will
|
||||
* be thrown.
|
||||
*
|
||||
* Note: JS::CallNonGenericMethod will only work correctly if it's called in
|
||||
* tail position in a JSNative. Do not call it from any other place.
|
||||
*/
|
||||
JS_ALWAYS_INLINE bool
|
||||
CallNonGenericMethod(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
if (test(thisv))
|
||||
return impl(cx, args);
|
||||
|
||||
return detail::CallMethodIfWrapped(cx, test, impl, args);
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/************************************************************************/
|
||||
@ -3955,7 +4042,7 @@ struct JSClass {
|
||||
* with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
|
||||
* prevously allowed, but is now an ES5 violation and thus unsupported.
|
||||
*/
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 8)
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 19)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
@ -4704,66 +4791,6 @@ JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
|
||||
|
||||
/*
|
||||
* Methods usually act upon |this| objects only from a single global object and
|
||||
* compartment. Sometimes, however, a method must act upon |this| values from
|
||||
* multiple global objects or compartments. In such cases the |this| value a
|
||||
* method might see will be wrapped, such that various access to the object --
|
||||
* to its class, its private data, its reserved slots, and so on -- will not
|
||||
* work properly without entering that object's compartment. This method
|
||||
* implements a solution to this problem.
|
||||
*
|
||||
* When called, this method attempts to unwrap |this| and call |native| on the
|
||||
* underlying object with the provided arguments, entering |this|'s compartment
|
||||
* in the process. It is critical that |this|-checking occur right at the
|
||||
* start of |native| so that reentrant invocation is idempotent! If the call
|
||||
* fails because |this| isn't a proxy to another object, a TypeError is thrown.
|
||||
*
|
||||
* The following example demonstrates the most common way this method might be
|
||||
* used, to accept objects having only a particular class but which might be
|
||||
* found in another compartment/global object or might be a proxy of some sort:
|
||||
*
|
||||
* static JSClass MyClass = { "MyClass", JSCLASS_HAS_PRIVATE, ... };
|
||||
*
|
||||
* inline bool
|
||||
* RequireMyClassThis(JSContext *cx, unsigned argc, JSObject **thisObj)
|
||||
* {
|
||||
* const Value &thisv = JS_THIS_VALUE(cx, vp);
|
||||
* if (!thisv.isObject()) {
|
||||
* JS_ReportError(cx, "this must be an object");
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* JSObject *obj = &thisv.toObject();
|
||||
* if (JS_GetClass(obj) == &MyClass) {
|
||||
* *thisObj = obj;
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* *thisObj = NULL; // prevent infinite recursion into calling method
|
||||
* return JS_CallNonGenericMethodOnProxy(cx, argc, vp, method, &MyClass);
|
||||
* }
|
||||
*
|
||||
* static JSBool
|
||||
* Method(JSContext *cx, unsigned argc, jsval *vp)
|
||||
* {
|
||||
* if (!RequireMyClassThis(cx, argc, vp, &thisObj))
|
||||
* return false;
|
||||
* if (!thisObj)
|
||||
* return true; // method invocation was performed by nested call
|
||||
*
|
||||
* // thisObj definitely has MyClass: implement the guts of the method.
|
||||
* void *priv = JS_GetPrivate(thisObj);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* This method doesn't do any checking of its own, except to throw a TypeError
|
||||
* if the |this| in the arguments isn't a proxy that can be unwrapped for the
|
||||
* recursive call. The client is responsible for performing all type-checks!
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native, JSClass *clasp);
|
||||
|
||||
/*
|
||||
* Given a buffer, return JS_FALSE if the buffer might become a valid
|
||||
* javascript statement with the addition of more lines. Otherwise return
|
||||
|
@ -95,7 +95,6 @@
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
@ -1443,17 +1442,18 @@ class ArraySharpDetector
|
||||
}
|
||||
};
|
||||
|
||||
static JSBool
|
||||
array_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsArray(const Value &v)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
return v.isObject() && v.toObject().isArray();
|
||||
}
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!obj->isArray())
|
||||
return HandleNonGenericMethodClassMismatch(cx, args, array_toSource, &ArrayClass);
|
||||
static bool
|
||||
array_toSource_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsArray(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> obj(cx, &args.thisv().toObject());
|
||||
|
||||
ArraySharpDetector detector(cx);
|
||||
if (!detector.init(obj))
|
||||
@ -1516,6 +1516,14 @@ array_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsArray, array_toSource_impl, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
class AutoArrayCycleDetector
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/BooleanObject-inl.h"
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/GlobalObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::types;
|
||||
@ -46,15 +46,20 @@ Class js::BooleanClass = {
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
static JSBool
|
||||
bool_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsBoolean(const Value &v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return v.isBoolean() || (v.isObject() && v.toObject().hasClass(&BooleanClass));
|
||||
}
|
||||
|
||||
bool b, ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, bool_toSource, &b, &ok))
|
||||
return ok;
|
||||
#if JS_HAS_TOSOURCE
|
||||
static bool
|
||||
bool_toSource_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
JS_ASSERT(IsBoolean(thisv));
|
||||
|
||||
bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().asBoolean().unbox();
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(cx, b, sb) || !sb.append("))"))
|
||||
@ -66,18 +71,41 @@ bool_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
bool_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsBoolean, bool_toSource_impl, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
bool_toString_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
JS_ASSERT(IsBoolean(thisv));
|
||||
|
||||
bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().asBoolean().unbox();
|
||||
args.rval().setString(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
bool_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsBoolean, bool_toString_impl, args);
|
||||
}
|
||||
|
||||
bool b, ok;
|
||||
if (!BoxedPrimitiveMethodGuard<bool>(cx, args, bool_toString, &b, &ok))
|
||||
return ok;
|
||||
static bool
|
||||
bool_valueOf_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
JS_ASSERT(IsBoolean(thisv));
|
||||
|
||||
args.rval().setString(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]);
|
||||
bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().asBoolean().unbox();
|
||||
args.rval().setBoolean(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -85,13 +113,7 @@ static JSBool
|
||||
bool_valueOf(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool b, ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, bool_valueOf, &b, &ok))
|
||||
return ok;
|
||||
|
||||
args.rval().setBoolean(b);
|
||||
return true;
|
||||
return CallNonGenericMethod(cx, IsBoolean, bool_valueOf_impl, args);
|
||||
}
|
||||
|
||||
static JSFunctionSpec boolean_methods[] = {
|
||||
@ -99,7 +121,6 @@ static JSFunctionSpec boolean_methods[] = {
|
||||
JS_FN(js_toSource_str, bool_toSource, 0, 0),
|
||||
#endif
|
||||
JS_FN(js_toString_str, bool_toString, 0, 0),
|
||||
JS_FN(js_valueOf_str, bool_valueOf, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
@ -143,6 +164,19 @@ js_InitBooleanClass(JSContext *cx, JSObject *obj)
|
||||
if (!DefinePropertiesAndBrand(cx, booleanProto, NULL, boolean_methods))
|
||||
return NULL;
|
||||
|
||||
Rooted<PropertyName*> valueOfName(cx, cx->runtime->atomState.valueOfAtom);
|
||||
Rooted<JSFunction*> valueOf(cx,
|
||||
js_NewFunction(cx, NULL, bool_valueOf, 0, 0, global, valueOfName));
|
||||
if (!valueOf)
|
||||
return NULL;
|
||||
if (!booleanProto->defineProperty(cx, valueOfName, ObjectValue(*valueOf),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
global->setBooleanValueOf(valueOf);
|
||||
|
||||
if (!DefineConstructorAndPrototype(cx, global, JSProto_Boolean, ctor, booleanProto))
|
||||
return NULL;
|
||||
|
||||
@ -160,21 +194,12 @@ namespace js {
|
||||
bool
|
||||
BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp)
|
||||
{
|
||||
JS_ASSERT(ObjectClassIs(obj, ESClass_Boolean, cx));
|
||||
JS_ASSERT(obj.isProxy());
|
||||
|
||||
/*
|
||||
* To respect the proxy abstraction, we can't simply unwrap and call
|
||||
* getPrimitiveThis on the wrapped object. All we know is that obj says
|
||||
* its [[Class]] is "Boolean". Boolean.prototype.valueOf is specified to
|
||||
* return the [[PrimitiveValue]] internal property, so call that instead.
|
||||
*/
|
||||
InvokeArgsGuard ag;
|
||||
if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
|
||||
return false;
|
||||
ag.calleev().setUndefined();
|
||||
ag.calleev() = cx->compartment->maybeGlobal()->booleanValueOf();
|
||||
ag.thisv().setObject(obj);
|
||||
if (!GetProxyHandler(&obj)->nativeCall(cx, &obj, &BooleanClass, bool_valueOf, ag))
|
||||
if (!Invoke(cx, ag))
|
||||
return false;
|
||||
*vp = ag.rval();
|
||||
return true;
|
||||
|
@ -376,7 +376,7 @@ JS_ALWAYS_INLINE bool
|
||||
CallJSNative(JSContext *cx, Native native, const CallArgs &args)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JSBool alreadyThrowing = cx->isExceptionPending();
|
||||
bool alreadyThrowing = cx->isExceptionPending();
|
||||
#endif
|
||||
assertSameCompartment(cx, args);
|
||||
bool ok = native(cx, args.length(), args.base());
|
||||
@ -387,6 +387,22 @@ CallJSNative(JSContext *cx, Native native, const CallArgs &args)
|
||||
return ok;
|
||||
}
|
||||
|
||||
STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
|
||||
JS_ALWAYS_INLINE bool
|
||||
CallNativeImpl(JSContext *cx, NativeImpl impl, const CallArgs &args)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
bool alreadyThrowing = cx->isExceptionPending();
|
||||
#endif
|
||||
assertSameCompartment(cx, args);
|
||||
bool ok = impl(cx, args);
|
||||
if (ok) {
|
||||
assertSameCompartment(cx, args.rval());
|
||||
JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
extern JSBool CallOrConstructBoundFunction(JSContext *, unsigned, js::Value *);
|
||||
|
||||
STATIC_PRECONDITION(ubound(args.argv_) >= argc)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,6 @@
|
||||
#include "frontend/TokenStream.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/ScopeObject.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
||||
@ -1348,3 +1347,45 @@ js_DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
|
||||
|
||||
return fun;
|
||||
}
|
||||
|
||||
void
|
||||
js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
|
||||
{
|
||||
Value &thisv = call.thisv();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (thisv.isObject()) {
|
||||
JS_ASSERT(thisv.toObject().getClass() != clasp ||
|
||||
!thisv.toObject().getProto() ||
|
||||
thisv.toObject().getProto()->getClass() != clasp);
|
||||
} else if (thisv.isString()) {
|
||||
JS_ASSERT(clasp != &StringClass);
|
||||
} else if (thisv.isNumber()) {
|
||||
JS_ASSERT(clasp != &NumberClass);
|
||||
} else if (thisv.isBoolean()) {
|
||||
JS_ASSERT(clasp != &BooleanClass);
|
||||
} else {
|
||||
JS_ASSERT(thisv.isUndefined() || thisv.isNull());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) {
|
||||
JSAutoByteString funNameBytes;
|
||||
if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
|
||||
clasp->name, funName, InformalValueTypeName(thisv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js::ReportIncompatible(JSContext *cx, CallReceiver call)
|
||||
{
|
||||
if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) {
|
||||
JSAutoByteString funNameBytes;
|
||||
if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_METHOD,
|
||||
funName, "method", InformalValueTypeName(call.thisv()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,6 +264,21 @@ XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope,
|
||||
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
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
#include "vm/String-inl.h"
|
||||
|
||||
@ -819,16 +818,18 @@ js_ThrowStopIteration(JSContext *cx)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
iterator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsIterator(const Value &v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return v.isObject() && v.toObject().hasClass(&IteratorClass);
|
||||
}
|
||||
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
iterator_next_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsIterator(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
if (!js_IteratorMore(cx, thisObj, &args.rval()))
|
||||
return false;
|
||||
@ -841,6 +842,13 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
return js_IteratorNext(cx, thisObj, &args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
iterator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsIterator, iterator_next_impl, args);
|
||||
}
|
||||
|
||||
#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
|
||||
|
||||
static JSFunctionSpec iterator_methods[] = {
|
||||
@ -1598,16 +1606,18 @@ CloseGenerator(JSContext *cx, JSObject *obj)
|
||||
return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, UndefinedValue());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
generator_send(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsGenerator(const Value &v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return v.isObject() && v.toObject().hasClass(&GeneratorClass);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, generator_send, &GeneratorClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
generator_send_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsGenerator(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
|
||||
if (!gen || gen->state == JSGEN_CLOSED) {
|
||||
@ -1633,15 +1643,18 @@ generator_send(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
generator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
generator_send(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsGenerator, generator_send_impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, generator_next, &GeneratorClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
generator_next_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsGenerator(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
|
||||
if (!gen || gen->state == JSGEN_CLOSED) {
|
||||
@ -1657,15 +1670,18 @@ generator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
generator_throw(JSContext *cx, unsigned argc, Value *vp)
|
||||
generator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsGenerator, generator_next_impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, generator_throw, &GeneratorClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
generator_throw_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsGenerator(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
|
||||
if (!gen || gen->state == JSGEN_CLOSED) {
|
||||
@ -1686,15 +1702,18 @@ generator_throw(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
generator_close(JSContext *cx, unsigned argc, Value *vp)
|
||||
generator_throw(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsGenerator, generator_throw_impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, generator_close, &GeneratorClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
generator_close_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsGenerator(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
|
||||
if (!gen || gen->state == JSGEN_CLOSED) {
|
||||
@ -1716,6 +1735,13 @@ generator_close(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
generator_close(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsGenerator, generator_close_impl, args);
|
||||
}
|
||||
|
||||
static JSFunctionSpec generator_methods[] = {
|
||||
JS_FN(js_next_str, generator_next, 0,JSPROP_ROPERM),
|
||||
JS_FN(js_send_str, generator_send, 1,JSPROP_ROPERM),
|
||||
|
134
js/src/jsnum.cpp
134
js/src/jsnum.cpp
@ -44,7 +44,6 @@
|
||||
#include "jslibmath.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
@ -53,7 +52,6 @@
|
||||
#include "jsnuminlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/NumberObject-inl.h"
|
||||
#include "vm/String-inl.h"
|
||||
|
||||
@ -465,19 +463,29 @@ Number(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
static JSBool
|
||||
num_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsNumber(const Value &v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return v.isNumber() || (v.isObject() && v.toObject().hasClass(&NumberClass));
|
||||
}
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, num_toSource, &d, &ok))
|
||||
return ok;
|
||||
inline double
|
||||
Extract(const Value &v)
|
||||
{
|
||||
if (v.isNumber())
|
||||
return v.toNumber();
|
||||
return v.toObject().asNumber().unbox();
|
||||
}
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
static bool
|
||||
num_toSource_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
double d = Extract(args.thisv());
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append("(new Number(") || !NumberValueToStringBuffer(cx, NumberValue(d), sb) ||
|
||||
if (!sb.append("(new Number(") ||
|
||||
!NumberValueToStringBuffer(cx, NumberValue(d), sb) ||
|
||||
!sb.append("))"))
|
||||
{
|
||||
return false;
|
||||
@ -489,6 +497,13 @@ num_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
num_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsNumber, num_toSource_impl, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
ToCStringBuf::ToCStringBuf() :dbuf(NULL)
|
||||
@ -578,15 +593,12 @@ IntToCString(ToCStringBuf *cbuf, int i, int base = 10)
|
||||
static JSString * JS_FASTCALL
|
||||
js_NumberToStringWithBase(JSContext *cx, double d, int base);
|
||||
|
||||
static JSBool
|
||||
num_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
num_toString_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ASSERT(IsNumber(args.thisv()));
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, num_toString, &d, &ok))
|
||||
return ok;
|
||||
double d = Extract(args.thisv());
|
||||
|
||||
int32_t base = 10;
|
||||
if (args.hasDefined(0)) {
|
||||
@ -611,14 +623,18 @@ num_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
num_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
|
||||
num_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsNumber, num_toString_impl, args);
|
||||
}
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, num_toLocaleString, &d, &ok))
|
||||
return ok;
|
||||
static bool
|
||||
num_toLocaleString_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsNumber(args.thisv()));
|
||||
|
||||
double d = Extract(args.thisv());
|
||||
|
||||
Rooted<JSString*> str(cx, js_NumberToStringWithBase(cx, d, 10));
|
||||
if (!str) {
|
||||
@ -739,18 +755,26 @@ num_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
num_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsNumber, num_toLocaleString_impl, args);
|
||||
}
|
||||
|
||||
static bool
|
||||
num_valueOf_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsNumber(args.thisv()));
|
||||
args.rval().setNumber(Extract(args.thisv()));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_num_valueOf(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, js_num_valueOf, &d, &ok))
|
||||
return ok;
|
||||
|
||||
args.rval().setNumber(d);
|
||||
return true;
|
||||
return CallNonGenericMethod(cx, IsNumber, num_valueOf_impl, args);
|
||||
}
|
||||
|
||||
|
||||
@ -794,15 +818,10 @@ DToStrResult(JSContext *cx, double d, JSDToStrMode mode, int precision, CallArgs
|
||||
* In the following three implementations, we allow a larger range of precision
|
||||
* than ECMA requires; this is permitted by ECMA-262.
|
||||
*/
|
||||
static JSBool
|
||||
num_toFixed(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
num_toFixed_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, num_toFixed, &d, &ok))
|
||||
return ok;
|
||||
JS_ASSERT(IsNumber(args.thisv()));
|
||||
|
||||
int precision;
|
||||
if (args.length() == 0) {
|
||||
@ -812,18 +831,20 @@ num_toFixed(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
return DToStrResult(cx, d, DTOSTR_FIXED, precision, args);
|
||||
return DToStrResult(cx, Extract(args.thisv()), DTOSTR_FIXED, precision, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
num_toExponential(JSContext *cx, unsigned argc, Value *vp)
|
||||
num_toFixed(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsNumber, num_toFixed_impl, args);
|
||||
}
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, num_toExponential, &d, &ok))
|
||||
return ok;
|
||||
static bool
|
||||
num_toExponential_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsNumber(args.thisv()));
|
||||
|
||||
JSDToStrMode mode;
|
||||
int precision;
|
||||
@ -836,18 +857,22 @@ num_toExponential(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
return DToStrResult(cx, d, mode, precision + 1, args);
|
||||
return DToStrResult(cx, Extract(args.thisv()), mode, precision + 1, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
num_toPrecision(JSContext *cx, unsigned argc, Value *vp)
|
||||
num_toExponential(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsNumber, num_toExponential_impl, args);
|
||||
}
|
||||
|
||||
double d;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, num_toPrecision, &d, &ok))
|
||||
return ok;
|
||||
static bool
|
||||
num_toPrecision_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsNumber(args.thisv()));
|
||||
|
||||
double d = Extract(args.thisv());
|
||||
|
||||
if (!args.hasDefined(0)) {
|
||||
JSString *str = js_NumberToStringWithBase(cx, d, 10);
|
||||
@ -873,6 +898,13 @@ num_toPrecision(JSContext *cx, unsigned argc, Value *vp)
|
||||
return DToStrResult(cx, d, mode, precision, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
num_toPrecision(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsNumber, num_toPrecision_impl, args);
|
||||
}
|
||||
|
||||
static JSFunctionSpec number_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN(js_toSource_str, num_toSource, 0, 0),
|
||||
|
@ -60,7 +60,9 @@
|
||||
#include "jsscopeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/BooleanObject-inl.h"
|
||||
#include "vm/NumberObject-inl.h"
|
||||
#include "vm/StringObject-inl.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
|
@ -902,20 +902,28 @@ static JSFunctionSpec json_static_methods[] = {
|
||||
JSObject *
|
||||
js_InitJSONClass(JSContext *cx, JSObject *obj_)
|
||||
{
|
||||
RootedObject obj(cx, obj_);
|
||||
Rooted<GlobalObject*> global(cx, &obj_->asGlobal());
|
||||
|
||||
RootedObject JSON(cx, NewObjectWithClassProto(cx, &JSONClass, NULL, obj));
|
||||
/*
|
||||
* JSON requires that Boolean.prototype.valueOf be created and stashed in a
|
||||
* reserved slot on the global object; see js::BooleanGetPrimitiveValueSlow
|
||||
* called from PreprocessValue above.
|
||||
*/
|
||||
if (!global->getOrCreateBooleanPrototype(cx))
|
||||
return NULL;
|
||||
|
||||
RootedObject JSON(cx, NewObjectWithClassProto(cx, &JSONClass, NULL, global));
|
||||
if (!JSON || !JSON->setSingletonType(cx))
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON),
|
||||
if (!JS_DefineProperty(cx, global, js_JSON_str, OBJECT_TO_JSVAL(JSON),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, 0))
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefineFunctions(cx, JSON, json_static_methods))
|
||||
return NULL;
|
||||
|
||||
MarkStandardClassInitializedNoProto(obj, &JSONClass);
|
||||
MarkStandardClassInitializedNoProto(global, &JSONClass);
|
||||
|
||||
return JSON;
|
||||
}
|
||||
|
@ -8,21 +8,21 @@
|
||||
#include <string.h>
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsfun.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsproxy.h"
|
||||
#include "jsscope.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
@ -318,10 +318,10 @@ BaseProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
|
||||
}
|
||||
|
||||
bool
|
||||
BaseProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
|
||||
BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
ReportIncompatibleMethod(cx, args, clasp);
|
||||
JS_ASSERT(OperationInProgress(cx, &args.thisv().toObject()));
|
||||
ReportIncompatible(cx, args);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -457,11 +457,16 @@ IndirectProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp,
|
||||
Native native, CallArgs args)
|
||||
IndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args)
|
||||
{
|
||||
args.thisv() = ObjectValue(*GetProxyTargetObject(proxy));
|
||||
return CallJSNative(cx, native, args);
|
||||
args.thisv() = ObjectValue(*GetProxyTargetObject(&args.thisv().toObject()));
|
||||
if (!test(args.thisv())) {
|
||||
ReportIncompatible(cx, args);
|
||||
return false;
|
||||
}
|
||||
|
||||
return CallNativeImpl(cx, impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1152,11 +1157,12 @@ Proxy::construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Val
|
||||
}
|
||||
|
||||
bool
|
||||
Proxy::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
|
||||
Proxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
Rooted<JSObject*> proxy(cx, &args.thisv().toObject());
|
||||
AutoPendingProxyOperation pending(cx, proxy);
|
||||
return GetProxyHandler(proxy)->nativeCall(cx, proxy, clasp, native, args);
|
||||
return GetProxyHandler(proxy)->nativeCall(cx, test, impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -102,7 +102,7 @@ class JS_FRIEND_API(BaseProxyHandler) {
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp);
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Value *rval);
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args);
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp);
|
||||
virtual JSType typeOf(JSContext *cx, JSObject *proxy);
|
||||
virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx);
|
||||
@ -150,8 +150,8 @@ class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *proxy, Class *clasp,
|
||||
Native native, CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *proxy, const Value *vp,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual JSType typeOf(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE;
|
||||
@ -226,7 +226,7 @@ class Proxy {
|
||||
/* Spidermonkey extensions. */
|
||||
static bool call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp);
|
||||
static bool construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Value *rval);
|
||||
static bool nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args);
|
||||
static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
|
||||
static bool hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp);
|
||||
static JSType typeOf(JSContext *cx, JSObject *proxy);
|
||||
static bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx);
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "jsstrinlines.h"
|
||||
#include "jsautooplen.h" // generated headers last
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
#include "vm/RegExpStatics-inl.h"
|
||||
#include "vm/StringObject-inl.h"
|
||||
@ -450,6 +449,12 @@ ThisToStringForStringProto(JSContext *cx, CallReceiver call)
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsString(const Value &v)
|
||||
{
|
||||
return v.isString() || (v.isObject() && v.toObject().hasClass(&StringClass));
|
||||
}
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
|
||||
/*
|
||||
@ -470,15 +475,14 @@ str_quote(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
str_toSource_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ASSERT(IsString(args.thisv()));
|
||||
|
||||
JSString *str;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, str_toSource, &str, &ok))
|
||||
return ok;
|
||||
Rooted<JSString*> str(cx, ToString(cx, args.thisv()));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
str = js_QuoteString(cx, str, '"');
|
||||
if (!str)
|
||||
@ -495,20 +499,31 @@ str_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsString, str_toSource_impl, args);
|
||||
}
|
||||
|
||||
#endif /* JS_HAS_TOSOURCE */
|
||||
|
||||
static bool
|
||||
str_toString_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsString(args.thisv()));
|
||||
|
||||
args.rval() = StringValue(args.thisv().isString()
|
||||
? args.thisv().toString()
|
||||
: args.thisv().toObject().asString().unbox());
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_str_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSString *str;
|
||||
bool ok;
|
||||
if (!BoxedPrimitiveMethodGuard(cx, args, js_str_toString, &str, &ok))
|
||||
return ok;
|
||||
|
||||
args.rval() = StringValue(str);
|
||||
return true;
|
||||
return CallNonGenericMethod(cx, IsString, str_toString_impl, args);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
#include "jstypedarrayinlines.h"
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
#include "vm/GlobalObject-inl.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace js;
|
||||
@ -117,32 +117,33 @@ getArrayBuffer(JSObject *obj)
|
||||
return obj ? &obj->asArrayBuffer() : NULL;
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsArrayBuffer(const Value &v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return v.isObject() && v.toObject().hasClass(&ArrayBufferClass);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, byteLengthGetter, &ArrayBufferClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JS_SET_RVAL(cx, vp, Int32Value(thisObj->asArrayBuffer().byteLength()));
|
||||
bool
|
||||
ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsArrayBuffer(args.thisv()));
|
||||
args.rval() = Int32Value(args.thisv().toObject().asArrayBuffer().byteLength());
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
|
||||
ArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsArrayBuffer, byteLengthGetterImpl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_slice, &ArrayBufferClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsArrayBuffer(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
ArrayBufferObject &arrayBuffer = thisObj->asArrayBuffer();
|
||||
|
||||
// these are the default values
|
||||
@ -169,6 +170,13 @@ ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsArrayBuffer, fun_slice_impl, args);
|
||||
}
|
||||
|
||||
/*
|
||||
* new ArrayBuffer(byteLength)
|
||||
*/
|
||||
@ -281,6 +289,37 @@ ArrayBufferObject::createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
|
||||
return create(cx, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayBufferObject::createDataViewForThisImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsArrayBuffer(args.thisv()));
|
||||
|
||||
/*
|
||||
* This method is only called for |DataView(alienBuf, ...)| which calls
|
||||
* this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|,
|
||||
* ergo there must be at least two arguments.
|
||||
*/
|
||||
JS_ASSERT(args.length() >= 2);
|
||||
|
||||
Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
|
||||
|
||||
Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
|
||||
|
||||
/*
|
||||
* Pop off the passed-along prototype and delegate to normal DataView
|
||||
* object construction.
|
||||
*/
|
||||
CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base());
|
||||
return DataViewObject::construct(cx, buffer, frobbedArgs, proto);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsArrayBuffer, createDataViewForThisImpl, args);
|
||||
}
|
||||
|
||||
void
|
||||
ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
@ -981,6 +1020,10 @@ class TypedArrayTemplate
|
||||
return &TypedArray::classes[ArrayTypeID()];
|
||||
}
|
||||
|
||||
static bool is(const Value &v) {
|
||||
return v.isObject() && v.toObject().hasClass(fastClass());
|
||||
}
|
||||
|
||||
static void
|
||||
obj_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
@ -1424,19 +1467,6 @@ class TypedArrayTemplate
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
fromBuffer(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject buffer(cx, &args[0].toObject());
|
||||
RootedObject proto(cx, &args[3].toObject());
|
||||
JSObject *obj = fromBuffer(cx, buffer, args[1].toInt32(), args[2].toInt32(), proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
create(JSContext *cx, unsigned argc, Value *argv)
|
||||
{
|
||||
@ -1494,27 +1524,32 @@ class TypedArrayTemplate
|
||||
return fromBuffer(cx, dataObj, byteOffset, length, proto);
|
||||
}
|
||||
|
||||
static bool IsThisClass(const Value &v) {
|
||||
return v.isObject() && v.toObject().hasClass(fastClass());
|
||||
}
|
||||
|
||||
template<Value ValueGetter(JSObject *obj)>
|
||||
static bool
|
||||
GetterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsThisClass(args.thisv()));
|
||||
args.rval() = ValueGetter(&args.thisv().toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
// ValueGetter is a function that takes an unwrapped typed array object and
|
||||
// returns a Value. Given such a function, Getter<> is a native that
|
||||
// retrieves a given Value, probably from a slot on the object.
|
||||
template<Value ValueGetter(JSObject *)>
|
||||
template<Value ValueGetter(JSObject *obj)>
|
||||
static JSBool
|
||||
Getter(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, Getter<ValueGetter>, fastClass(), &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JS_SET_RVAL(cx, vp, ValueGetter(thisObj));
|
||||
return true;
|
||||
return CallNonGenericMethod(cx, IsThisClass, GetterImpl<ValueGetter>, args);
|
||||
}
|
||||
|
||||
// Define an accessor for a read-only property that invokes a native getter
|
||||
template<Value ValueGetter(JSObject *)>
|
||||
template<Value ValueGetter(JSObject *obj)>
|
||||
static bool
|
||||
DefineGetter(JSContext *cx, PropertyName *name, HandleObject proto)
|
||||
{
|
||||
@ -1550,18 +1585,12 @@ class TypedArrayTemplate
|
||||
}
|
||||
|
||||
/* subarray(start[, end]) */
|
||||
static JSBool
|
||||
fun_subarray(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
fun_subarray_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ASSERT(IsThisClass(args.thisv()));
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_subarray, fastClass(), &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JSObject *tarray = getTypedArray(thisObj);
|
||||
JSObject *tarray = getTypedArray(&args.thisv().toObject());
|
||||
if (!tarray)
|
||||
return true;
|
||||
|
||||
@ -1589,17 +1618,18 @@ class TypedArrayTemplate
|
||||
return true;
|
||||
}
|
||||
|
||||
/* move(begin, end, dest) */
|
||||
static JSBool
|
||||
fun_move(JSContext *cx, unsigned argc, Value *vp)
|
||||
fun_subarray(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsThisClass, fun_subarray_impl, args);
|
||||
}
|
||||
|
||||
JSObject *obj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_move, fastClass(), &obj))
|
||||
return false;
|
||||
if (!obj)
|
||||
return true;
|
||||
/* move(begin, end, dest) */
|
||||
static bool
|
||||
fun_move_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsThisClass(args.thisv()));
|
||||
|
||||
if (args.length() < 3) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
@ -1610,7 +1640,7 @@ class TypedArrayTemplate
|
||||
uint32_t srcEnd;
|
||||
uint32_t dest;
|
||||
|
||||
JSObject *tarray = getTypedArray(obj);
|
||||
JSObject *tarray = getTypedArray(&args.thisv().toObject());
|
||||
uint32_t length = TypedArray::length(tarray);
|
||||
if (!ToClampedIndex(cx, args[0], length, &srcBegin) ||
|
||||
!ToClampedIndex(cx, args[1], length, &srcEnd) ||
|
||||
@ -1651,18 +1681,20 @@ class TypedArrayTemplate
|
||||
return true;
|
||||
}
|
||||
|
||||
/* set(array[, offset]) */
|
||||
static JSBool
|
||||
fun_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
fun_move(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsThisClass, fun_move_impl, args);
|
||||
}
|
||||
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, fun_set, fastClass(), thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
/* set(array[, offset]) */
|
||||
static bool
|
||||
fun_set_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsThisClass(args.thisv()));
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
RootedObject tarray(cx, getTypedArray(thisObj));
|
||||
if (!tarray)
|
||||
return true;
|
||||
@ -1720,6 +1752,13 @@ class TypedArrayTemplate
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
fun_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsThisClass, fun_set_impl, args);
|
||||
}
|
||||
|
||||
public:
|
||||
static JSObject *
|
||||
fromBuffer(JSContext *cx, HandleObject bufobj, int32_t byteOffsetInt, int32_t lengthInt,
|
||||
@ -1752,23 +1791,31 @@ class TypedArrayTemplate
|
||||
* set to the origin compartment's prototype object, not the
|
||||
* target's (specifically, the actual view in the target
|
||||
* compartment will use as its prototype a wrapper around the
|
||||
* origin compartment's view.prototype object)
|
||||
* origin compartment's view.prototype object).
|
||||
*
|
||||
* Rather than hack some crazy solution together, implement
|
||||
* this all using a private helper function, created when
|
||||
* ArrayBuffer was initialized and cached in the global. This
|
||||
* reuses all the existing cross-compartment crazy so we don't
|
||||
* have to do anything *uniquely* crazy here.
|
||||
*/
|
||||
JSObject *proto = GetProtoForClass(cx, fastClass());
|
||||
Rooted<JSObject*> proto(cx, GetProtoForClass(cx, fastClass()));
|
||||
if (!proto)
|
||||
return NULL;
|
||||
Value argv[] = { UndefinedValue(),
|
||||
MagicValue(JS_IS_CONSTRUCTING),
|
||||
ObjectValue(*bufobj),
|
||||
Int32Value(byteOffsetInt),
|
||||
Int32Value(lengthInt),
|
||||
ObjectValue(*proto) };
|
||||
uint32_t argc = sizeof(argv) / sizeof(argv[0]) - 2;
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, argv);
|
||||
if (!Proxy::nativeCall(cx, bufobj, &ArrayBufferClass, fromBuffer, args))
|
||||
InvokeArgsGuard ag;
|
||||
if (!cx->stack.pushInvokeArgs(cx, 3, &ag))
|
||||
return NULL;
|
||||
return &args.rval().toObject();
|
||||
|
||||
ag.calleev() = cx->compartment->maybeGlobal()->createArrayFromBuffer<NativeType>();
|
||||
ag.thisv() = ObjectValue(*bufobj);
|
||||
ag[0] = Int32Value(byteOffsetInt);
|
||||
ag[1] = Int32Value(lengthInt);
|
||||
ag[2] = ObjectValue(*proto);
|
||||
|
||||
if (!Invoke(cx, ag))
|
||||
return NULL;
|
||||
return &ag.rval().toObject();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2173,6 +2220,34 @@ class Uint8ClampedArray : public TypedArrayTemplate<uint8_clamped> {
|
||||
static JSFunctionSpec jsfuncs[];
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
ArrayBufferObject::createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
typedef TypedArrayTemplate<T> ArrayType;
|
||||
JS_ASSERT(IsArrayBuffer(args.thisv()));
|
||||
JS_ASSERT(args.length() == 3);
|
||||
|
||||
Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
|
||||
Rooted<JSObject*> proto(cx, &args[2].toObject());
|
||||
|
||||
Rooted<JSObject*> obj(cx);
|
||||
obj = ArrayType::fromBuffer(cx, buffer, args[0].toInt32(), args[1].toInt32(), proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.rval() = ObjectValue(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSBool
|
||||
ArrayBufferObject::createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
typedef TypedArrayTemplate<T> ArrayType;
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsArrayBuffer, createTypedArrayFromBufferImpl<T>, args);
|
||||
}
|
||||
|
||||
// this default implementation is only valid for integer types
|
||||
// less than 32-bits in size.
|
||||
template<typename NativeType>
|
||||
@ -2294,21 +2369,6 @@ DataViewObject::construct(JSContext *cx, JSObject *bufobj, const CallArgs &args,
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::constructWithProto(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
// Pop the proto argument off the end
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JSObject &proto = args[args.length() - 1].toObject();
|
||||
|
||||
// And now mimic class_constructor for everything else, but pass in the proto
|
||||
args = CallArgsFromVp(argc - 1, vp);
|
||||
RootedObject bufobj(cx);
|
||||
if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
|
||||
return false;
|
||||
return construct(cx, bufobj, args, &proto);
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -2319,23 +2379,21 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
|
||||
if (bufobj->isWrapper() && UnwrapObject(bufobj)->isArrayBuffer()) {
|
||||
JSObject *proto = GetProtoForClass(cx, &DataViewClass);
|
||||
Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
|
||||
Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
Vector<Value, 6> argv(cx);
|
||||
argv.resize(argc + 2 + 1);
|
||||
memcpy(argv.begin(), args.base(), sizeof(Value) * (argc + 2));
|
||||
argv[argc + 2].setObject(*proto);
|
||||
argv[0].setUndefined(); // We want to use a different callee (avoid an assertion)
|
||||
|
||||
// Appease 'thisv' assertion in CrossCompartmentWrapper::nativeCall
|
||||
argv[1].setMagic(JS_IS_CONSTRUCTING);
|
||||
|
||||
CallArgs proxyArgs = CallArgsFromVp(argc + 1, argv.begin());
|
||||
if (!Proxy::nativeCall(cx, bufobj, &DataViewClass, constructWithProto, proxyArgs))
|
||||
InvokeArgsGuard ag;
|
||||
if (!cx->stack.pushInvokeArgs(cx, argc + 1, &ag))
|
||||
return false;
|
||||
args.rval() = proxyArgs.rval();
|
||||
ag.calleev() = global->createDataViewForThis();
|
||||
ag.thisv() = ObjectValue(*bufobj);
|
||||
PodCopy(ag.array(), args.array(), args.length());
|
||||
ag[argc] = ObjectValue(*proto);
|
||||
if (!Invoke(cx, ag))
|
||||
return false;
|
||||
args.rval() = ag.rval();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2509,18 +2567,12 @@ DataViewObject::write(JSContext *cx, Handle<DataViewObject*> obj,
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
bool
|
||||
DataViewObject::getInt8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getInt8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
int8_t val;
|
||||
if (!read(cx, thisView, args, &val, "getInt8"))
|
||||
@ -2530,17 +2582,18 @@ DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getInt8Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getUint8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getUint8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
uint8_t val;
|
||||
if (!read(cx, thisView, args, &val, "getUint8"))
|
||||
@ -2550,17 +2603,18 @@ DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getUint8Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getInt16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getInt16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
int16_t val;
|
||||
if (!read(cx, thisView, args, &val, "getInt16"))
|
||||
@ -2570,17 +2624,18 @@ DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getInt16Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getUint16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getUint16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
uint16_t val;
|
||||
if (!read(cx, thisView, args, &val, "getUint16"))
|
||||
@ -2590,17 +2645,18 @@ DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getUint16Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getInt32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getInt32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
int32_t val;
|
||||
if (!read(cx, thisView, args, &val, "getInt32"))
|
||||
@ -2610,17 +2666,18 @@ DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getInt32Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getUint32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getUint32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
uint32_t val;
|
||||
if (!read(cx, thisView, args, &val, "getUint32"))
|
||||
@ -2630,17 +2687,18 @@ DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getUint32Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getFloat32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getFloat32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
float val;
|
||||
if (!read(cx, thisView, args, &val, "getFloat32"))
|
||||
@ -2651,17 +2709,18 @@ DataViewObject::fun_getFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
DataViewObject::fun_getFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getFloat32Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getFloat64, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::getFloat64Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
double val;
|
||||
if (!read(cx, thisView, args, &val, "getFloat64"))
|
||||
@ -2671,20 +2730,41 @@ DataViewObject::fun_getFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getFloat64Impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
DataViewObject::setInt8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<int8_t>(cx, thisView, args, "setInt8"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setInt8Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setInt8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setUint8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<int8_t>(cx, thisView, args, "setInt8"))
|
||||
if (!write<uint8_t>(cx, thisView, args, "setUint8"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2694,16 +2774,17 @@ JSBool
|
||||
DataViewObject::fun_setUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setUint8Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setUint8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setInt16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<uint8_t>(cx, thisView, args, "setUint8"))
|
||||
if (!write<int16_t>(cx, thisView, args, "setInt16"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2713,16 +2794,17 @@ JSBool
|
||||
DataViewObject::fun_setInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setInt16Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setInt16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setUint16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<int16_t>(cx, thisView, args, "setInt16"))
|
||||
if (!write<uint16_t>(cx, thisView, args, "setUint16"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2732,16 +2814,17 @@ JSBool
|
||||
DataViewObject::fun_setUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setUint16Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setUint16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setInt32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<uint16_t>(cx, thisView, args, "setUint16"))
|
||||
if (!write<int32_t>(cx, thisView, args, "setInt32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2751,16 +2834,17 @@ JSBool
|
||||
DataViewObject::fun_setInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setInt32Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setInt32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setUint32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<int32_t>(cx, thisView, args, "setInt32"))
|
||||
if (!write<uint32_t>(cx, thisView, args, "setUint32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2770,16 +2854,17 @@ JSBool
|
||||
DataViewObject::fun_setUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setUint32Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setUint32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setFloat32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<uint32_t>(cx, thisView, args, "setUint32"))
|
||||
if (!write<float>(cx, thisView, args, "setFloat32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2789,16 +2874,17 @@ JSBool
|
||||
DataViewObject::fun_setFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, setFloat32Impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setFloat32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
bool
|
||||
DataViewObject::setFloat64Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
|
||||
if (!write<float>(cx, thisView, args, "setFloat32"))
|
||||
if (!write<double>(cx, thisView, args, "setFloat64"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2808,19 +2894,7 @@ JSBool
|
||||
DataViewObject::fun_setFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setFloat64, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &thisObj->asDataView());
|
||||
|
||||
if (!write<double>(cx, thisView, args, "setFloat64"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
return CallNonGenericMethod(cx, is, setFloat64Impl, args);
|
||||
}
|
||||
|
||||
/***
|
||||
@ -3073,9 +3147,19 @@ InitTypedArrayClass(JSContext *cx)
|
||||
if (!JS_DefineFunctions(cx, proto, ArrayType::jsfuncs))
|
||||
return NULL;
|
||||
|
||||
Rooted<JSFunction*> fun(cx);
|
||||
fun =
|
||||
js_NewFunction(cx, NULL,
|
||||
ArrayBufferObject::createTypedArrayFromBuffer<typename ArrayType::ThisType>,
|
||||
0, 0, global, NULL);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
if (!DefineConstructorAndPrototype(cx, global, ArrayType::key, ctor, proto))
|
||||
return NULL;
|
||||
|
||||
global->setCreateArrayFromBuffer<typename ArrayType::ThisType>(fun);
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
@ -3205,31 +3289,33 @@ JSFunctionSpec DataViewObject::jsfuncs[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
template<Value ValueGetter(DataViewObject &)>
|
||||
static JSBool
|
||||
DataViewGetter(JSContext *cx, unsigned argc, Value *vp)
|
||||
template<Value ValueGetter(DataViewObject &view)>
|
||||
bool
|
||||
DataViewObject::getterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, DataViewGetter<ValueGetter>, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JS_SET_RVAL(cx, vp, ValueGetter(thisObj->asDataView()));
|
||||
args.rval() = ValueGetter(args.thisv().toObject().asDataView());
|
||||
return true;
|
||||
}
|
||||
|
||||
template<Value ValueGetter(DataViewObject&)>
|
||||
template<Value ValueGetter(DataViewObject &view)>
|
||||
JSBool
|
||||
DataViewObject::getter(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, getterImpl<ValueGetter>, args);
|
||||
}
|
||||
|
||||
template<Value ValueGetter(DataViewObject &view)>
|
||||
bool
|
||||
DefineDataViewGetter(JSContext *cx, PropertyName *name, HandleObject proto)
|
||||
DataViewObject::defineGetter(JSContext *cx, PropertyName *name, HandleObject proto)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER;
|
||||
|
||||
Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
|
||||
JSObject *getter = js_NewFunction(cx, NULL, DataViewGetter<ValueGetter>, 0, 0, global, NULL);
|
||||
JSObject *getter = js_NewFunction(cx, NULL, DataViewObject::getter<ValueGetter>, 0, 0, global, NULL);
|
||||
if (!getter)
|
||||
return false;
|
||||
|
||||
@ -3254,21 +3340,33 @@ DataViewObject::initClass(JSContext *cx)
|
||||
if (!LinkConstructorAndPrototype(cx, ctor, proto))
|
||||
return NULL;
|
||||
|
||||
if (!DefineDataViewGetter<bufferValue>(cx, cx->runtime->atomState.bufferAtom, proto))
|
||||
if (!defineGetter<bufferValue>(cx, cx->runtime->atomState.bufferAtom, proto))
|
||||
return NULL;
|
||||
|
||||
if (!DefineDataViewGetter<byteLengthValue>(cx, cx->runtime->atomState.byteLengthAtom, proto))
|
||||
if (!defineGetter<byteLengthValue>(cx, cx->runtime->atomState.byteLengthAtom, proto))
|
||||
return NULL;
|
||||
|
||||
if (!DefineDataViewGetter<byteOffsetValue>(cx, cx->runtime->atomState.byteOffsetAtom, proto))
|
||||
if (!defineGetter<byteOffsetValue>(cx, cx->runtime->atomState.byteOffsetAtom, proto))
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefineFunctions(cx, proto, DataViewObject::jsfuncs))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Create a helper function to implement the craziness of
|
||||
* |new DataView(new otherWindow.ArrayBuffer())|, and install it in the
|
||||
* global for use by the DataView constructor.
|
||||
*/
|
||||
Rooted<JSFunction*> fun(cx);
|
||||
fun = js_NewFunction(cx, NULL, ArrayBufferObject::createDataViewForThis, 0, 0, global, NULL);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
if (!DefineConstructorAndPrototype(cx, global, JSProto_DataView, ctor, proto))
|
||||
return NULL;
|
||||
|
||||
global->setCreateDataViewForThis(fun);
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
@ -3550,5 +3648,7 @@ JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx)
|
||||
if (!(obj = CheckedUnwrap(cx, obj)))
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
return obj->isDataView() ? obj->asDataView().byteLength() : TypedArray::byteLengthValue(obj).toInt32();
|
||||
return obj->isDataView()
|
||||
? obj->asDataView().byteLength()
|
||||
: TypedArray::byteLengthValue(obj).toInt32();
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ namespace js {
|
||||
*/
|
||||
class ArrayBufferObject : public JSObject
|
||||
{
|
||||
static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
|
||||
static bool fun_slice_impl(JSContext *cx, CallArgs args);
|
||||
|
||||
public:
|
||||
static Class protoClass;
|
||||
static JSFunctionSpec jsfuncs[];
|
||||
@ -42,6 +45,17 @@ class ArrayBufferObject : public JSObject
|
||||
static JSObject *createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
|
||||
uint32_t begin, uint32_t end);
|
||||
|
||||
static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
|
||||
static JSBool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
template<typename T>
|
||||
static bool
|
||||
createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);
|
||||
|
||||
template<typename T>
|
||||
static JSBool
|
||||
createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static void
|
||||
obj_trace(JSTracer *trc, JSObject *obj);
|
||||
|
||||
@ -140,6 +154,7 @@ class ArrayBufferObject : public JSObject
|
||||
* ArrayBuffer.prototype and neutered ArrayBuffers.
|
||||
*/
|
||||
inline bool hasData() const;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
@ -271,6 +286,20 @@ class DataViewObject : public JSObject
|
||||
static const size_t BYTELENGTH_SLOT = 1;
|
||||
static const size_t BUFFER_SLOT = 2;
|
||||
|
||||
static inline bool is(const Value &v);
|
||||
|
||||
template<Value ValueGetter(DataViewObject &view)>
|
||||
static bool
|
||||
getterImpl(JSContext *cx, CallArgs args);
|
||||
|
||||
template<Value ValueGetter(DataViewObject &view)>
|
||||
static JSBool
|
||||
getter(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
template<Value ValueGetter(DataViewObject &view)>
|
||||
static bool
|
||||
defineGetter(JSContext *cx, PropertyName *name, HandleObject proto);
|
||||
|
||||
public:
|
||||
static const size_t RESERVED_SLOTS = 3;
|
||||
|
||||
@ -286,22 +315,54 @@ class DataViewObject : public JSObject
|
||||
create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
Handle<ArrayBufferObject*> arrayBuffer, JSObject *proto);
|
||||
|
||||
static bool getInt8Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getInt8(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getUint8Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getUint8(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getInt16Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getInt16(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getUint16Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getUint16(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getInt32Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getInt32(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getUint32Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getUint32(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getFloat32Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getFloat32(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool getFloat64Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_getFloat64(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setInt8Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setInt8(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setUint8Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setUint8(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setInt16Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setInt16(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setUint16Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setUint16(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setInt32Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setInt32(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setUint32Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setUint32(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setFloat32Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool setFloat64Impl(JSContext *cx, CallArgs args);
|
||||
static JSBool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
inline uint32_t byteLength();
|
||||
inline uint32_t byteOffset();
|
||||
inline JSObject & arrayBuffer();
|
||||
|
@ -59,57 +59,67 @@ ClampIntForUint8Array(int32_t x)
|
||||
}
|
||||
|
||||
inline Value
|
||||
TypedArray::lengthValue(JSObject *obj) {
|
||||
TypedArray::lengthValue(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getFixedSlot(FIELD_LENGTH);
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
TypedArray::length(JSObject *obj) {
|
||||
TypedArray::length(JSObject *obj)
|
||||
{
|
||||
return lengthValue(obj).toInt32();
|
||||
}
|
||||
|
||||
inline Value
|
||||
TypedArray::byteOffsetValue(JSObject *obj) {
|
||||
TypedArray::byteOffsetValue(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getFixedSlot(FIELD_BYTEOFFSET);
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
TypedArray::byteOffset(JSObject *obj) {
|
||||
TypedArray::byteOffset(JSObject *obj)
|
||||
{
|
||||
return byteOffsetValue(obj).toInt32();
|
||||
}
|
||||
|
||||
inline Value
|
||||
TypedArray::byteLengthValue(JSObject *obj) {
|
||||
TypedArray::byteLengthValue(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getFixedSlot(FIELD_BYTELENGTH);
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
TypedArray::byteLength(JSObject *obj) {
|
||||
TypedArray::byteLength(JSObject *obj)
|
||||
{
|
||||
return byteLengthValue(obj).toInt32();
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
TypedArray::type(JSObject *obj) {
|
||||
TypedArray::type(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getFixedSlot(FIELD_TYPE).toInt32();
|
||||
}
|
||||
|
||||
inline Value
|
||||
TypedArray::bufferValue(JSObject *obj) {
|
||||
TypedArray::bufferValue(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getFixedSlot(FIELD_BUFFER);
|
||||
}
|
||||
|
||||
inline ArrayBufferObject *
|
||||
TypedArray::buffer(JSObject *obj) {
|
||||
TypedArray::buffer(JSObject *obj)
|
||||
{
|
||||
return &bufferValue(obj).toObject().asArrayBuffer();
|
||||
}
|
||||
|
||||
inline void *
|
||||
TypedArray::viewData(JSObject *obj) {
|
||||
TypedArray::viewData(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return (void *)obj->getPrivate(NUM_FIXED_SLOTS);
|
||||
}
|
||||
@ -141,6 +151,12 @@ TypedArray::slotWidth(JSObject *obj) {
|
||||
return slotWidth(type(obj));
|
||||
}
|
||||
|
||||
bool
|
||||
DataViewObject::is(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&DataViewClass);
|
||||
}
|
||||
|
||||
inline DataViewObject *
|
||||
DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
Handle<ArrayBufferObject*> arrayBuffer, JSObject *proto)
|
||||
|
@ -19,8 +19,6 @@
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/MethodGuard-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
namespace js {
|
||||
@ -120,16 +118,16 @@ GetKeyArg(JSContext *cx, CallArgs &args)
|
||||
return JS_UnwrapObject(&key);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
IsWeakMap(const Value &v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return v.isObject() && v.toObject().hasClass(&WeakMapClass);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
WeakMap_has_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -140,10 +138,8 @@ WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (map) {
|
||||
ObjectValueMap::Ptr ptr = map->lookup(key);
|
||||
if (ptr) {
|
||||
if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) {
|
||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||
args.rval() = BooleanValue(true);
|
||||
return true;
|
||||
}
|
||||
@ -154,15 +150,16 @@ WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
|
||||
WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsWeakMap, WeakMap_has_impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
WeakMap_get_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -173,10 +170,8 @@ WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (map) {
|
||||
ObjectValueMap::Ptr ptr = map->lookup(key);
|
||||
if (ptr) {
|
||||
if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) {
|
||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||
args.rval() = ptr->value;
|
||||
return true;
|
||||
}
|
||||
@ -187,15 +182,16 @@ WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
|
||||
WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsWeakMap, WeakMap_get_impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
WeakMap_delete_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -206,10 +202,8 @@ WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (map) {
|
||||
ObjectValueMap::Ptr ptr = map->lookup(key);
|
||||
if (ptr) {
|
||||
if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) {
|
||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||
map->remove(ptr);
|
||||
args.rval() = BooleanValue(true);
|
||||
return true;
|
||||
@ -221,15 +215,16 @@ WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsWeakMap, WeakMap_delete_impl, args);
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
static bool
|
||||
WeakMap_set_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -242,18 +237,22 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
Value value = (args.length() > 1) ? args[1] : UndefinedValue();
|
||||
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (!map) {
|
||||
map = cx->new_<ObjectValueMap>(cx, thisObj);
|
||||
map = cx->new_<ObjectValueMap>(cx, thisObj.get());
|
||||
if (!map->init()) {
|
||||
cx->delete_(map);
|
||||
goto out_of_memory;
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
thisObj->setPrivate(map);
|
||||
}
|
||||
|
||||
if (!map->put(key, value))
|
||||
goto out_of_memory;
|
||||
if (!map->put(key, value)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preserve wrapped native keys to prevent wrapper optimization.
|
||||
if (key->getClass()->ext.isWrappedNative) {
|
||||
@ -265,10 +264,13 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
out_of_memory:
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
static JSBool
|
||||
WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, IsWeakMap, WeakMap_set_impl, args);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
|
@ -304,10 +304,11 @@ DirectWrapper::construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value
|
||||
}
|
||||
|
||||
bool
|
||||
DirectWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args)
|
||||
DirectWrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
|
||||
{
|
||||
const jsid id = JSID_VOID;
|
||||
CHECKED(IndirectProxyHandler::nativeCall(cx, wrapper, clasp, native, args), CALL);
|
||||
Rooted<JSObject*> wrapper(cx, &args.thisv().toObject());
|
||||
CHECKED(IndirectProxyHandler::nativeCall(cx, test, impl, args), CALL);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -715,12 +716,14 @@ CrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper_, unsigned a
|
||||
}
|
||||
|
||||
bool
|
||||
CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs srcArgs)
|
||||
CrossCompartmentWrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs srcArgs)
|
||||
{
|
||||
JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) || &srcArgs.thisv().toObject() == wrapper);
|
||||
JS_ASSERT(!UnwrapObject(wrapper)->isCrossCompartmentWrapper());
|
||||
Rooted<JSObject*> wrapper(cx, &srcArgs.thisv().toObject());
|
||||
JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) ||
|
||||
!UnwrapObject(wrapper)->isCrossCompartmentWrapper());
|
||||
|
||||
JSObject *wrapped = wrappedObject(wrapper);
|
||||
Rooted<JSObject*> wrapped(cx, wrappedObject(wrapper));
|
||||
AutoCompartment call(cx, wrapped);
|
||||
if (!call.enter())
|
||||
return false;
|
||||
@ -732,13 +735,13 @@ CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *cla
|
||||
Value *src = srcArgs.base();
|
||||
Value *srcend = srcArgs.array() + srcArgs.length();
|
||||
Value *dst = dstArgs.base();
|
||||
for (; src != srcend; ++src, ++dst) {
|
||||
for (; src < srcend; ++src, ++dst) {
|
||||
*dst = *src;
|
||||
if (!call.destination->wrap(cx, dst))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CallJSNative(cx, native, dstArgs))
|
||||
if (!CallNonGenericMethod(cx, test, impl, dstArgs))
|
||||
return false;
|
||||
|
||||
srcArgs.rval() = dstArgs.rval();
|
||||
@ -828,14 +831,14 @@ SecurityWrapper<Base>::SecurityWrapper(unsigned flags)
|
||||
|
||||
template <class Base>
|
||||
bool
|
||||
SecurityWrapper<Base>::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native,
|
||||
SecurityWrapper<Base>::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args)
|
||||
{
|
||||
/*
|
||||
* Let this through until compartment-per-global lets us have stronger
|
||||
* invariants wrt document.domain (bug 714547).
|
||||
*/
|
||||
return Base::nativeCall(cx, wrapper, clasp, native, args);
|
||||
return Base::nativeCall(cx, test, impl, args);
|
||||
}
|
||||
|
||||
template <class Base>
|
||||
@ -882,7 +885,8 @@ class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp);
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Value *rval);
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args);
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp);
|
||||
virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx);
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *proxy);
|
||||
@ -967,8 +971,7 @@ DeadObjectProxy::construct(JSContext *cx, JSObject *wrapper, unsigned argc,
|
||||
}
|
||||
|
||||
bool
|
||||
DeadObjectProxy::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp,
|
||||
Native native, CallArgs args)
|
||||
DeadObjectProxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEAD_OBJECT);
|
||||
return false;
|
||||
|
@ -202,7 +202,8 @@ class JS_FRIEND_API(DirectWrapper) : public Wrapper, public DirectProxyHandler
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) MOZ_OVERRIDE;
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent) MOZ_OVERRIDE;
|
||||
@ -243,7 +244,8 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public DirectWrapper
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) MOZ_OVERRIDE;
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent) MOZ_OVERRIDE;
|
||||
@ -268,7 +270,8 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
|
||||
public:
|
||||
SecurityWrapper(unsigned flags);
|
||||
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual bool regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g) MOZ_OVERRIDE;
|
||||
};
|
||||
|
@ -41,7 +41,6 @@ size_t sE4XObjectsCreated = 0;
|
||||
#include "frontend/TokenStream.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
|
@ -35,7 +35,7 @@ l = <><a>text</a></>;
|
||||
actual = l.charAt(0);
|
||||
TEST(4, expect, actual);
|
||||
|
||||
expect = 'TypeError: String.prototype.toString called on incompatible XML';
|
||||
expect = "TypeError";
|
||||
|
||||
delete XML.prototype.function::toString;
|
||||
var xml = <a>TEXT</a>;
|
||||
@ -44,13 +44,13 @@ delete Object.prototype.toString;
|
||||
try {
|
||||
actual = xml.toString();
|
||||
} catch(ex) {
|
||||
actual = ex + '';
|
||||
actual = ex.name;
|
||||
} finally {
|
||||
Object.prototype.toString = saveToString;
|
||||
}
|
||||
TEST(7, expect, actual);
|
||||
|
||||
expect = 'TypeError: String.prototype.toString called on incompatible XML';
|
||||
expect = "TypeError";
|
||||
try
|
||||
{
|
||||
var x = <a><name/></a>;
|
||||
@ -59,7 +59,7 @@ try
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
actual = ex.name;
|
||||
}
|
||||
TEST(8, expect, actual);
|
||||
|
||||
@ -71,7 +71,7 @@ try
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
actual = ex.name;
|
||||
}
|
||||
TEST(9, expect, actual);
|
||||
|
||||
|
@ -34,14 +34,14 @@ function test()
|
||||
{
|
||||
try
|
||||
{
|
||||
expect = 'TypeError: Array.prototype.toSource called on incompatible String';
|
||||
actual = Array.prototype.toSource.call((new String('foo')));
|
||||
Array.prototype.toSource.call(new String('foo'));
|
||||
throw new Error("didn't throw");
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
assertEq(ex instanceof TypeError, true,
|
||||
"wrong error thrown: expected TypeError, got " + ex);
|
||||
}
|
||||
assertEq(actual, expect, summary);
|
||||
}
|
||||
|
||||
reportCompare(true, true, "Tests complete");
|
||||
|
@ -23,7 +23,7 @@ function allTests()
|
||||
assertEq(d == DS, true);
|
||||
|
||||
var d2 = new Date(2010, 1, 1);
|
||||
d2.valueOf = function() { return 17; };
|
||||
d2.valueOf = function() { assertEq(arguments.length, 0); return 17; };
|
||||
assertEq(d2 == DS, true);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
@ -36,7 +36,7 @@ function allTests()
|
||||
assertEq(d == DS, true);
|
||||
|
||||
var d2 = new Date(2010, 1, 1);
|
||||
d2.valueOf = function() { return 17; };
|
||||
d2.valueOf = function() { assertEq(arguments.length, 0); return 17; };
|
||||
assertEq(d2 == DS, true);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
@ -56,7 +56,7 @@ function allTests()
|
||||
assertEq(d2 + 3, 9 + 3);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
d3.valueOf = function() { return 17; };
|
||||
d3.valueOf = function() { assertEq(arguments.length, 0); return 17; };
|
||||
assertEq(d3 + 5, DS + "5");
|
||||
|
||||
function testDateNumberAddition()
|
||||
@ -69,7 +69,7 @@ function allTests()
|
||||
assertEq(d2 + 3, 9 + 3);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
d3.valueOf = function() { return 17; };
|
||||
d3.valueOf = function() { assertEq(arguments.length, 0); return 17; };
|
||||
assertEq(d3 + 5, DS + "5");
|
||||
}
|
||||
testDateNumberAddition();
|
||||
@ -85,7 +85,7 @@ function allTests()
|
||||
assertEq(d2 + d2, 10);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
d3.valueOf = function() { return 8.5; };
|
||||
d3.valueOf = function() { assertEq(arguments.length, 0); return 8.5; };
|
||||
assertEq(d3 + d3, DS + DS);
|
||||
|
||||
function testDateDateAddition()
|
||||
@ -98,7 +98,7 @@ function allTests()
|
||||
assertEq(d2 + d2, 10);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
d3.valueOf = function() { return 8.5; };
|
||||
d3.valueOf = function() { assertEq(arguments.length, 0); return 8.5; };
|
||||
assertEq(d3 + d3, DS + DS);
|
||||
}
|
||||
testDateDateAddition();
|
||||
@ -113,7 +113,7 @@ function allTests()
|
||||
assertEq(obj[d], 17);
|
||||
|
||||
var d2 = new Date(2010, 1, 1);
|
||||
d2.valueOf = function() { return 8; }
|
||||
d2.valueOf = function() { assertEq(arguments.length, 0); return 8; }
|
||||
assertEq(obj[d2], 17);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
@ -129,7 +129,7 @@ function allTests()
|
||||
assertEq(obj[d], 17);
|
||||
|
||||
var d2 = new Date(2010, 1, 1);
|
||||
d2.valueOf = function() { return 8; }
|
||||
d2.valueOf = function() { assertEq(arguments.length, 0); return 8; }
|
||||
assertEq(obj[d2], 17);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
@ -152,7 +152,7 @@ function allTests()
|
||||
assertEq(d2 in { baz: 42 }, true);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
d3.valueOf = function() { return "quux"; };
|
||||
d3.valueOf = function() { assertEq(arguments.length, 0); return "quux"; };
|
||||
assertEq(d3 in obj, true);
|
||||
|
||||
function testInOperatorName()
|
||||
@ -168,7 +168,7 @@ function allTests()
|
||||
assertEq(d2 in { baz: 42 }, true);
|
||||
|
||||
var d3 = new Date(2010, 1, 1);
|
||||
d3.valueOf = function() { return "quux"; };
|
||||
d3.valueOf = function() { assertEq(arguments.length, 0); return "quux"; };
|
||||
assertEq(d3 in obj, true);
|
||||
}
|
||||
testInOperatorName();
|
||||
|
@ -3,46 +3,35 @@
|
||||
* 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/. */
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 380933;
|
||||
var summary = 'Do not assert with uneval object with setter with modified proto';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
test();
|
||||
//-----------------------------------------------------------------------------
|
||||
var f = (function(){});
|
||||
var y =
|
||||
Object.defineProperty({}, "p",
|
||||
{
|
||||
get: f,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
f.__proto__ = [];
|
||||
|
||||
function test()
|
||||
try
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
var f = (function(){});
|
||||
var y =
|
||||
Object.defineProperty({}, "p",
|
||||
{
|
||||
get: f,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
f.__proto__ = [];
|
||||
|
||||
expect = /TypeError: Array.prototype.toSource called on incompatible Function/;
|
||||
try
|
||||
{
|
||||
uneval(y);
|
||||
actual = 'No Error';
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
}
|
||||
|
||||
reportMatch(expect, actual, summary);
|
||||
|
||||
exitFunc ('test');
|
||||
uneval(y);
|
||||
throw new Error("didn't throw");
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
assertEq(ex instanceof TypeError, true,
|
||||
"wrong exception thrown: expected TypeError, got " + ex);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "jsinterp.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/Stack.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
||||
|
@ -59,6 +59,153 @@ GlobalObject::setOriginalEval(JSObject *evalobj)
|
||||
setSlot(EVAL, ObjectValue(*evalobj));
|
||||
}
|
||||
|
||||
void
|
||||
GlobalObject::setCreateArrayFromBufferHelper(uint32_t slot, Handle<JSFunction*> fun)
|
||||
{
|
||||
JS_ASSERT(getSlotRef(slot).isUndefined());
|
||||
setSlot(slot, ObjectValue(*fun));
|
||||
}
|
||||
|
||||
void
|
||||
GlobalObject::setBooleanValueOf(Handle<JSFunction*> valueOfFun)
|
||||
{
|
||||
JS_ASSERT(getSlotRef(BOOLEAN_VALUEOF).isUndefined());
|
||||
setSlot(BOOLEAN_VALUEOF, ObjectValue(*valueOfFun));
|
||||
}
|
||||
|
||||
void
|
||||
GlobalObject::setCreateDataViewForThis(Handle<JSFunction*> fun)
|
||||
{
|
||||
JS_ASSERT(getSlotRef(CREATE_DATAVIEW_FOR_THIS).isUndefined());
|
||||
setSlot(CREATE_DATAVIEW_FOR_THIS, ObjectValue(*fun));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<uint8_t>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<int8_t>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_INT8, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<uint16_t>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_UINT16, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<int16_t>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_INT16, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<uint32_t>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_UINT32, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<int32_t>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_INT32, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<float>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT32, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<double>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT64, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void
|
||||
GlobalObject::setCreateArrayFromBuffer<uint8_clamped>(Handle<JSFunction*> fun)
|
||||
{
|
||||
setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED, fun);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<uint8_t>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_UINT8);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<int8_t>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_INT8);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<uint16_t>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_UINT16);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<int16_t>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_INT16);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<uint32_t>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_UINT32);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<int32_t>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_INT32);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<float>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_FLOAT32);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<double>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_FLOAT64);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Value
|
||||
GlobalObject::createArrayFromBuffer<uint8_clamped>() const
|
||||
{
|
||||
return createArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif
|
||||
|
@ -315,11 +315,13 @@ GlobalObject::clear(JSContext *cx)
|
||||
setSlot(RUNTIME_CODEGEN_ENABLED, UndefinedValue());
|
||||
|
||||
/*
|
||||
* Clear the original-eval and [[ThrowTypeError]] slots, in case throwing
|
||||
* trying to execute a script for this global must reinitialize standard
|
||||
* classes. See bug 470150.
|
||||
* Clear all slots storing function values, in case throwing trying to
|
||||
* execute a script for this global must reinitialize standard classes.
|
||||
* See bug 470150.
|
||||
*/
|
||||
setSlot(BOOLEAN_VALUEOF, UndefinedValue());
|
||||
setSlot(EVAL, UndefinedValue());
|
||||
setSlot(CREATE_DATAVIEW_FOR_THIS, UndefinedValue());
|
||||
setSlot(THROWTYPEERROR, UndefinedValue());
|
||||
|
||||
/*
|
||||
|
@ -69,14 +69,32 @@ class GlobalObject : public JSObject
|
||||
*/
|
||||
static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3;
|
||||
|
||||
/* Various function values needed by the engine. */
|
||||
static const unsigned BOOLEAN_VALUEOF = STANDARD_CLASS_SLOTS;
|
||||
static const unsigned EVAL = BOOLEAN_VALUEOF + 1;
|
||||
static const unsigned CREATE_DATAVIEW_FOR_THIS = EVAL + 1;
|
||||
static const unsigned THROWTYPEERROR = CREATE_DATAVIEW_FOR_THIS + 1;
|
||||
|
||||
/*
|
||||
* Instances of the internal createArrayFromBuffer function used by the
|
||||
* typed array code, one per typed array element type.
|
||||
*/
|
||||
static const unsigned FROM_BUFFER_UINT8 = THROWTYPEERROR + 1;
|
||||
static const unsigned FROM_BUFFER_INT8 = FROM_BUFFER_UINT8 + 1;
|
||||
static const unsigned FROM_BUFFER_UINT16 = FROM_BUFFER_INT8 + 1;
|
||||
static const unsigned FROM_BUFFER_INT16 = FROM_BUFFER_UINT16 + 1;
|
||||
static const unsigned FROM_BUFFER_UINT32 = FROM_BUFFER_INT16 + 1;
|
||||
static const unsigned FROM_BUFFER_INT32 = FROM_BUFFER_UINT32 + 1;
|
||||
static const unsigned FROM_BUFFER_FLOAT32 = FROM_BUFFER_INT32 + 1;
|
||||
static const unsigned FROM_BUFFER_FLOAT64 = FROM_BUFFER_FLOAT32 + 1;
|
||||
static const unsigned FROM_BUFFER_UINT8CLAMPED = FROM_BUFFER_FLOAT64 + 1;
|
||||
|
||||
/* One-off properties stored after slots for built-ins. */
|
||||
static const unsigned THROWTYPEERROR = STANDARD_CLASS_SLOTS;
|
||||
static const unsigned GENERATOR_PROTO = THROWTYPEERROR + 1;
|
||||
static const unsigned GENERATOR_PROTO = FROM_BUFFER_UINT8CLAMPED + 1;
|
||||
static const unsigned REGEXP_STATICS = GENERATOR_PROTO + 1;
|
||||
static const unsigned FUNCTION_NS = REGEXP_STATICS + 1;
|
||||
static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
|
||||
static const unsigned EVAL = RUNTIME_CODEGEN_ENABLED + 1;
|
||||
static const unsigned FLAGS = EVAL + 1;
|
||||
static const unsigned FLAGS = RUNTIME_CODEGEN_ENABLED + 1;
|
||||
static const unsigned DEBUGGERS = FLAGS + 1;
|
||||
|
||||
/* Total reserved-slot count for global objects. */
|
||||
@ -110,7 +128,6 @@ class GlobalObject : public JSObject
|
||||
inline void setFunctionClassDetails(JSFunction *ctor, JSObject *proto);
|
||||
|
||||
inline void setThrowTypeError(JSFunction *fun);
|
||||
|
||||
inline void setOriginalEval(JSObject *evalobj);
|
||||
|
||||
Value getConstructor(JSProtoKey key) const {
|
||||
@ -157,6 +174,30 @@ class GlobalObject : public JSObject
|
||||
bool errorClassesInitialized() const {
|
||||
return classIsInitialized(JSProto_Error);
|
||||
}
|
||||
bool dataViewClassInitialized() const {
|
||||
return classIsInitialized(JSProto_DataView);
|
||||
}
|
||||
bool typedArrayClassesInitialized() const {
|
||||
// This alias exists only for clarity: in reality all the typed array
|
||||
// classes constitute a (semi-)coherent whole.
|
||||
return classIsInitialized(JSProto_DataView);
|
||||
}
|
||||
|
||||
Value createArrayFromBufferHelper(uint32_t slot) const {
|
||||
JS_ASSERT(typedArrayClassesInitialized());
|
||||
JS_ASSERT(FROM_BUFFER_UINT8 <= slot && slot <= FROM_BUFFER_UINT8CLAMPED);
|
||||
return getSlot(slot);
|
||||
}
|
||||
|
||||
inline void setCreateArrayFromBufferHelper(uint32_t slot, Handle<JSFunction*> fun);
|
||||
|
||||
public:
|
||||
/* XXX Privatize me! */
|
||||
inline void setBooleanValueOf(Handle<JSFunction*> valueOfFun);
|
||||
inline void setCreateDataViewForThis(Handle<JSFunction*> fun);
|
||||
|
||||
template<typename T>
|
||||
inline void setCreateArrayFromBuffer(Handle<JSFunction*> fun);
|
||||
|
||||
public:
|
||||
static GlobalObject *create(JSContext *cx, Class *clasp);
|
||||
@ -277,6 +318,15 @@ class GlobalObject : public JSObject
|
||||
return &self->getSlot(GENERATOR_PROTO).toObject();
|
||||
}
|
||||
|
||||
JSObject *getOrCreateDataViewPrototype(JSContext *cx) {
|
||||
if (dataViewClassInitialized())
|
||||
return &getPrototype(JSProto_DataView).toObject();
|
||||
Rooted<GlobalObject*> self(cx, this);
|
||||
if (!js_InitTypedArrayClasses(cx, this))
|
||||
return NULL;
|
||||
return &self->getPrototype(JSProto_DataView).toObject();
|
||||
}
|
||||
|
||||
inline RegExpStatics *getRegExpStatics() const;
|
||||
|
||||
JSObject *getThrowTypeError() const {
|
||||
@ -284,6 +334,19 @@ class GlobalObject : public JSObject
|
||||
return &getSlot(THROWTYPEERROR).toObject();
|
||||
}
|
||||
|
||||
Value booleanValueOf() const {
|
||||
JS_ASSERT(booleanClassInitialized());
|
||||
return getSlot(BOOLEAN_VALUEOF);
|
||||
}
|
||||
|
||||
Value createDataViewForThis() const {
|
||||
JS_ASSERT(dataViewClassInitialized());
|
||||
return getSlot(CREATE_DATAVIEW_FOR_THIS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Value createArrayFromBuffer() const;
|
||||
|
||||
void clear(JSContext *cx);
|
||||
|
||||
bool isCleared() const {
|
||||
|
@ -1,94 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* 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 MethodGuard_inl_h___
|
||||
#define MethodGuard_inl_h___
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "MethodGuard.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "BooleanObject-inl.h"
|
||||
#include "NumberObject-inl.h"
|
||||
#include "StringObject-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T> class PrimitiveBehavior { };
|
||||
|
||||
template<>
|
||||
class PrimitiveBehavior<bool> {
|
||||
public:
|
||||
static inline bool isType(const Value &v) { return v.isBoolean(); }
|
||||
static inline bool extract(const Value &v) { return v.toBoolean(); }
|
||||
static inline bool extract(JSObject &obj) { return obj.asBoolean().unbox(); }
|
||||
static inline Class *getClass() { return &BooleanClass; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class PrimitiveBehavior<double> {
|
||||
public:
|
||||
static inline bool isType(const Value &v) { return v.isNumber(); }
|
||||
static inline double extract(const Value &v) { return v.toNumber(); }
|
||||
static inline double extract(JSObject &obj) { return obj.asNumber().unbox(); }
|
||||
static inline Class *getClass() { return &NumberClass; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class PrimitiveBehavior<JSString *> {
|
||||
public:
|
||||
static inline bool isType(const Value &v) { return v.isString(); }
|
||||
static inline JSString *extract(const Value &v) { return v.toString(); }
|
||||
static inline JSString *extract(JSObject &obj) { return obj.asString().unbox(); }
|
||||
static inline Class *getClass() { return &StringClass; }
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
inline bool
|
||||
NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, JSObject **thisObj)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
if (thisv.isObject()) {
|
||||
JSObject &obj = thisv.toObject();
|
||||
if (obj.getClass() == clasp) {
|
||||
*thisObj = &obj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*thisObj = NULL;
|
||||
return HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool
|
||||
BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok)
|
||||
{
|
||||
typedef detail::PrimitiveBehavior<T> Behavior;
|
||||
|
||||
const Value &thisv = args.thisv();
|
||||
if (Behavior::isType(thisv)) {
|
||||
*v = Behavior::extract(thisv);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *thisObj;
|
||||
*ok = NonGenericMethodGuard(cx, args, native, Behavior::getClass(), &thisObj);
|
||||
if (!*ok || !thisObj)
|
||||
return false;
|
||||
*v = Behavior::extract(*thisObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* MethodGuard_inl_h___ */
|
@ -1,59 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
#include "jsproxy.h"
|
||||
|
||||
#include "MethodGuard.h"
|
||||
#include "Stack.h"
|
||||
|
||||
#include "jsfuninlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
void
|
||||
js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
|
||||
{
|
||||
Value &thisv = call.thisv();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (thisv.isObject()) {
|
||||
JS_ASSERT(thisv.toObject().getClass() != clasp ||
|
||||
!thisv.toObject().getProto() ||
|
||||
thisv.toObject().getProto()->getClass() != clasp);
|
||||
} else if (thisv.isString()) {
|
||||
JS_ASSERT(clasp != &StringClass);
|
||||
} else if (thisv.isNumber()) {
|
||||
JS_ASSERT(clasp != &NumberClass);
|
||||
} else if (thisv.isBoolean()) {
|
||||
JS_ASSERT(clasp != &BooleanClass);
|
||||
} else {
|
||||
JS_ASSERT(thisv.isUndefined() || thisv.isNull());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) {
|
||||
JSAutoByteString funNameBytes;
|
||||
if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
|
||||
clasp->name, funName, InformalValueTypeName(thisv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
js::HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp)
|
||||
{
|
||||
if (args.thisv().isObject()) {
|
||||
JSObject &thisObj = args.thisv().toObject();
|
||||
if (thisObj.isProxy())
|
||||
return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
|
||||
}
|
||||
|
||||
ReportIncompatibleMethod(cx, args, clasp);
|
||||
return false;
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
/* Method prologue type-checking and unwrapping of the this parameter. */
|
||||
|
||||
#ifndef MethodGuard_h___
|
||||
#define MethodGuard_h___
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Report an error if call.thisv is not compatible with the specified class.
|
||||
*
|
||||
* NB: most callers should be calling or NonGenericMethodGuard,
|
||||
* HandleNonGenericMethodClassMismatch, or BoxedPrimitiveMethodGuard (so that
|
||||
* transparent proxies are handled correctly). Thus, any caller of this
|
||||
* function better have a good explanation for why proxies are being handled
|
||||
* correctly (e.g., by IsCallable) or are not an issue (E4X).
|
||||
*/
|
||||
extern void
|
||||
ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
|
||||
|
||||
/*
|
||||
* A non-generic method is specified to report an error if args.thisv is not an
|
||||
* object with a specific [[Class]] internal property (ES5 8.6.2).
|
||||
* NonGenericMethodGuard performs this checking. Canonical usage is:
|
||||
*
|
||||
* CallArgs args = ...
|
||||
* JSObject *thisObj;
|
||||
* if (!NonGenericMethodGuard(cx, args, clasp, &thisObj))
|
||||
* return false;
|
||||
* if (!thisObj)
|
||||
* return true;
|
||||
*
|
||||
* Specifically: if args.thisv is a proxy, NonGenericMethodGuard will call its
|
||||
* ProxyHandler's nativeCall hook (which may recursively call args.callee in
|
||||
* args.thisv's compartment). These are the possible post-conditions:
|
||||
*
|
||||
* 1. NonGenericMethodGuard returned false because it encountered an error:
|
||||
* args.thisv wasn't an object, was an object of the wrong class, was a
|
||||
* proxy to an object of the wrong class, or was a proxy to an object of
|
||||
* the right class but the recursive call to args.callee failed. This case
|
||||
* should be handled like any other failure: propagate it, or catch it and
|
||||
* continue.
|
||||
* 2. NonGenericMethodGuard returned true, and thisObj was nulled out. In
|
||||
* this case args.thisv was a proxy to an object with the desired class,
|
||||
* and recursive invocation of args.callee succeeded. This completes the
|
||||
* invocation of args.callee, so return true.
|
||||
* 3. NonGenericMethodGuard returned true, and thisObj was set to a non-null
|
||||
* pointer. In this case args.thisv was exactly an object of the desired
|
||||
* class, and not a proxy to one. Finish up the call using thisObj as the
|
||||
* this object provided to the call, which will have clasp as its class.
|
||||
*
|
||||
* Be careful! This guard may reenter the native, so the guard must be placed
|
||||
* before any effectful operations are performed.
|
||||
*/
|
||||
inline bool
|
||||
NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, JSObject **thisObj);
|
||||
|
||||
/*
|
||||
* NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than
|
||||
* one class is acceptable (viz., isDenseArray() || isSlowArray()), the caller
|
||||
* may test the class and delegate to HandleNonGenericMethodClassMismatch to
|
||||
* handle the proxy case and error reporting. The 'clasp' argument is only used
|
||||
* for error reporting (clasp->name).
|
||||
*/
|
||||
extern bool
|
||||
HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp);
|
||||
|
||||
/*
|
||||
* Implement the extraction of a primitive from a value as needed for the
|
||||
* toString, valueOf, and a few other methods of the boxed primitives classes
|
||||
* Boolean, Number, and String (e.g., ES5 15.6.4.2). If 'true' is returned, the
|
||||
* extracted primitive is stored in |*v|. If 'false' is returned, the caller
|
||||
* must immediately 'return *ok'. For details, see NonGenericMethodGuard.
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool
|
||||
BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* MethodGuard_h___ */
|
Loading…
Reference in New Issue
Block a user