Bug 770344 - Experiment implementing __proto__ as an accessor. r=luke

This commit is contained in:
Jeff Walden 2012-06-27 18:35:56 -07:00
Родитель 2e645f31ef
Коммит 68e5a1ecb2
16 изменённых файлов: 424 добавлений и 170 удалений

Просмотреть файл

@ -4042,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 + 19)
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 20)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

Просмотреть файл

@ -452,7 +452,9 @@ JS_GetE4XObjectsCreated(JSContext *)
return sE4XObjectsCreated;
}
namespace js {
extern size_t sSetProtoCalled;
}
JS_FRIEND_API(size_t)
JS_SetProtoCalled(JSContext *)

Просмотреть файл

@ -103,60 +103,6 @@ JS_ObjectToOuterObject(JSContext *cx, JSObject *obj_)
return GetOuterObject(cx, obj);
}
#if JS_HAS_OBJ_PROTO_PROP
static JSBool
obj_getProto(JSContext *cx, HandleObject obj, HandleId id, Value *vp);
static JSBool
obj_setProto(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);
JSPropertySpec object_props[] = {
{js_proto_str, 0, JSPROP_PERMANENT|JSPROP_SHARED, obj_getProto, obj_setProto},
{0,0,0,0,0}
};
static JSBool
obj_getProto(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
{
/* Let CheckAccess get the slot's value, based on the access mode. */
unsigned attrs;
RootedId nid(cx, NameToId(cx->runtime->atomState.protoAtom));
return CheckAccess(cx, obj, nid, JSACC_PROTO, vp, &attrs);
}
size_t sSetProtoCalled = 0;
static JSBool
obj_setProto(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
{
if (!cx->runningWithTrustedPrincipals())
++sSetProtoCalled;
/* ECMAScript 5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */
if (!obj->isExtensible()) {
obj->reportNotExtensible(cx);
return false;
}
if (!vp->isObjectOrNull())
return true;
RootedObject pobj(cx, vp->toObjectOrNull());
unsigned attrs;
RootedId nid(cx, NameToId(cx->runtime->atomState.protoAtom));
if (!CheckAccess(cx, obj, nid, JSAccessMode(JSACC_PROTO|JSACC_WRITE), vp, &attrs))
return false;
return SetProto(cx, obj, pobj, true);
}
#else /* !JS_HAS_OBJ_PROTO_PROP */
#define object_props NULL
#endif /* !JS_HAS_OBJ_PROTO_PROP */
static bool
MarkSharpObjects(JSContext *cx, HandleObject obj, JSIdArray **idap, JSSharpInfo *value)
{
@ -1057,28 +1003,43 @@ obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
}
#endif /* OLD_GETTER_SETTER_METHODS */
/* ES5 15.2.3.2. */
JSBool
obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
{
if (argc == 0) {
js_ReportMissingArg(cx, *vp, 0);
return JS_FALSE;
CallArgs args = CallArgsFromVp(argc, vp);
/* Step 1. */
if (args.length() == 0) {
js_ReportMissingArg(cx, args.calleev(), 0);
return false;
}
if (vp[2].isPrimitive()) {
if (args[0].isPrimitive()) {
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, vp[2], NULL);
if (!bytes)
return JS_FALSE;
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
JS_free(cx, bytes);
return JS_FALSE;
return false;
}
JSObject *obj = &vp[2].toObject();
unsigned attrs;
RootedId nid(cx, NameToId(cx->runtime->atomState.protoAtom));
return CheckAccess(cx, obj, nid, JSACC_PROTO, vp, &attrs);
/* Step 2. */
/*
* Implement [[Prototype]]-getting -- particularly across compartment
* boundaries -- by calling a cached __proto__ getter function.
*/
InvokeArgsGuard nested;
if (!cx->stack.pushInvokeArgs(cx, 0, &nested))
return false;
nested.calleev() = cx->global()->protoGetter();
nested.thisv() = args[0];
if (!Invoke(cx, nested))
return false;
args.rval() = nested.rval();
return true;
}
namespace js {

Просмотреть файл

@ -1062,12 +1062,6 @@ js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, js::HandleObject ob
extern JSBool
js_PropertyIsEnumerable(JSContext *cx, js::HandleObject obj, js::HandleId id, js::Value *vp);
#if JS_HAS_OBJ_PROTO_PROP
extern JSPropertySpec object_props[];
#else
#define object_props NULL
#endif
extern JSFunctionSpec object_methods[];
extern JSFunctionSpec object_static_methods[];

Просмотреть файл

@ -751,6 +751,8 @@ class ScriptedProxyHandler : public IndirectProxyHandler {
virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp);
/* Spidermonkey extensions. */
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) MOZ_OVERRIDE;
virtual JSType typeOf(JSContext *cx, JSObject *proxy);
virtual bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
@ -960,6 +962,14 @@ ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, V
ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
}
bool
ScriptedProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args)
{
return BaseProxyHandler::nativeCall(cx, test, impl, args);
}
JSType
ScriptedProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
{

Просмотреть файл

@ -550,49 +550,6 @@ ArrayBufferObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
if (!delegate)
return false;
if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) {
// setting __proto__ = null
// effectively removes the prototype chain.
// any attempt to set __proto__ on native
// objects after setting them to null makes
// __proto__ just a plain property.
// the following code simulates this behaviour on arrays.
//
// we first attempt to set the prototype on
// the delegate which is a native object
// so that existing code handles the case
// of treating it as special or plain.
// if the delegate's prototype has now changed
// then we change our prototype too.
//
// otherwise __proto__ was a plain property
// and we don't modify our prototype chain
// since obj_getProperty will fetch it as a plain
// property from the delegate.
RootedObject oldDelegateProto(cx, delegate->getProto());
if (!baseops::SetPropertyHelper(cx, delegate, delegate, id, 0, vp, strict))
return false;
if (delegate->getProto() != oldDelegateProto) {
// actual __proto__ was set and not a plain property called
// __proto__
if (!obj->isExtensible()) {
obj->reportNotExtensible(cx);
return false;
}
Rooted<JSObject*> newProto(cx, vp->toObjectOrNull());
if (!SetProto(cx, obj, newProto, true)) {
// this can be caused for example by setting x.__proto__ = x
// restore delegate prototype chain
SetProto(cx, delegate, oldDelegateProto, true);
return false;
}
}
return true;
}
return baseops::SetPropertyHelper(cx, delegate, obj, id, 0, vp, strict);
}

Просмотреть файл

@ -0,0 +1,53 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = '__proto__.js';
var BUGNUMBER = 770344;
var summary = "__proto__ as accessor";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var protoDesc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
assertEq(protoDesc !== null, true);
assertEq(typeof protoDesc, "object");
assertEq(protoDesc.hasOwnProperty("get"), true);
assertEq(protoDesc.hasOwnProperty("set"), true);
assertEq(protoDesc.hasOwnProperty("enumerable"), true);
assertEq(protoDesc.hasOwnProperty("configurable"), true);
assertEq(protoDesc.hasOwnProperty("value"), false);
assertEq(protoDesc.hasOwnProperty("writable"), false);
assertEq(protoDesc.configurable, true);
assertEq(protoDesc.enumerable, false);
assertEq(typeof protoDesc.get, "function", protoDesc.get + "");
assertEq(typeof protoDesc.set, "function", protoDesc.set + "");
assertEq(delete Object.prototype.__proto__, true);
assertEq(Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"),
undefined);
var obj = {};
obj.__proto__ = 5;
assertEq(Object.getPrototypeOf(obj), Object.prototype);
assertEq(obj.hasOwnProperty("__proto__"), true);
var desc = Object.getOwnPropertyDescriptor(obj, "__proto__");
assertEq(desc !== null, true);
assertEq(typeof desc, "object");
assertEq(desc.value, 5);
assertEq(desc.writable, true);
assertEq(desc.enumerable, true);
assertEq(desc.configurable, true);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

Просмотреть файл

@ -0,0 +1,54 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs newGlobal()
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 770344;
var summary = "Object.getPrototypeOf behavior across compartments";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var other = newGlobal();
var getProto = Object.getPrototypeOf;
var otherGetProto = other.Object.getPrototypeOf;
var proto = {};
var obj = Object.create(proto);
assertEq(getProto(obj), proto);
assertEq(otherGetProto(obj), proto);
other.proto = proto;
var otherObj = other.evaluate("Object.create(proto)");
assertEq(getProto(otherObj), proto);
assertEq(otherGetProto(otherObj), proto);
var p = other.evaluate("({})");
var objOtherProto = Object.create(p);
assertEq(getProto(objOtherProto), p);
assertEq(otherGetProto(objOtherProto), p);
other.evaluate("var otherProto = { otherProto: 1 }; " +
"var otherObj = Object.create(otherProto);");
assertEq(getProto(other.otherObj), other.otherProto);
assertEq(otherGetProto(other.otherObj), other.otherProto);
other.evaluate("var newOtherProto = { newOtherProto: 1 }; " +
"otherObj.__proto__ = newOtherProto;");
assertEq(otherGetProto(other.otherObj), other.newOtherProto);
Math.sin();
assertEq(getProto(other.otherObj), other.newOtherProto);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

Просмотреть файл

@ -0,0 +1,90 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = 'proxy-__proto__.js';
var BUGNUMBER = 770344;
var summary = "Behavior of __proto__ on proxies";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var protoDesc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
var protoGetter = protoDesc.get;
var protoSetter = protoDesc.set;
function pp(arr)
{
return arr.map(function(v) { return "" + v; }).join(", ");
}
function testProxy(creator, args, proto)
{
print("Now testing behavior for " +
"Proxy." + creator + "(" + pp(args) + ")");
var pobj = Proxy[creator].apply(Proxy, args);
// Check [[Prototype]] before attempted mutation
assertEq(Object.getPrototypeOf(pobj), proto);
assertEq(protoGetter.call(pobj), proto);
// Attempt [[Prototype]] mutation
try
{
protoSetter.call(pobj);
throw new Error("should throw trying to mutate a proxy's [[Prototype]]");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"expected TypeError, instead got: " + e);
}
// Check [[Prototype]] after attempted mutation
assertEq(Object.getPrototypeOf(pobj), proto);
assertEq(protoGetter.call(pobj), proto);
}
// Proxy object with non-null [[Prototype]]
var nonNullProto = { toString: function() { return "non-null prototype"; } };
var nonNullHandler = { toString: function() { return "non-null handler"; } };
testProxy("create", [nonNullHandler, nonNullProto], nonNullProto);
// Proxy object with null [[Prototype]]
var nullProto = null;
var nullHandler = { toString: function() { return "null handler"; } };
testProxy("create", [nullHandler, nullProto], nullProto);
// Proxy function with [[Call]]
var callForCallOnly = function () { };
callForCallOnly.toString = function() { return "callForCallOnly"; };
var callOnlyHandler = { toString: function() { return "call-only handler"; } };
testProxy("createFunction",
[callOnlyHandler, callForCallOnly], Function.prototype);
// Proxy function with [[Call]] and [[Construct]]
var callForCallConstruct = function() { };
callForCallConstruct.toString = function() { return "call/construct call"; };
var constructForCallConstruct = function() { };
constructForCallConstruct.toString =
function() { return "call/construct construct"; };
var handlerForCallConstruct =
{ toString: function() { return "call/construct handler"; } };
testProxy("createFunction",
[handlerForCallConstruct,
callForCallConstruct,
constructForCallConstruct],
Function.prototype);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

Просмотреть файл

@ -11,18 +11,11 @@ var expect = 'No Crash';
printBugNumber(BUGNUMBER);
printStatus (summary);
try
{
this.__proto__ = [];
this.unwatch("x");
}
catch(ex)
{
print(ex + '');
if (typeof window != 'undefined')
{
expect = 'Error: invalid __proto__ value (can only be set to null)';
}
actual = ex + '';
}
reportCompare(expect, actual, summary);
this.__proto__ = [];
this.unwatch("x");
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

Просмотреть файл

@ -11,11 +11,6 @@ print(BUGNUMBER + ": " + summary);
* BEGIN TEST *
**************/
var x = { prop: "value" };
var a = new ArrayBuffer([]);
a.__proto__ = x;
assertEq(a.prop, "value");
ArrayBuffer.prototype.prop = "on prototype";
var b = new ArrayBuffer([]);
assertEq(b.prop, "on prototype");
@ -25,6 +20,9 @@ assertEq(c.prop, "on prototype");
c.prop = "direct";
assertEq(c.prop, "direct");
assertEq(ArrayBuffer.prototype.prop, "on prototype");
assertEq(new ArrayBuffer([]).prop, "on prototype");
assertEq(c.nonexistent, undefined);
reportCompare(true, true);

Просмотреть файл

@ -1,18 +1,16 @@
var x = new ArrayBuffer(2);
var test = function() {
var test = function(newProto) {
try {
x.__proto__ = x;
x.__proto__ = newProto;
return false;
} catch(e) {
return true;
}
}
assertEq(test(), true);
assertEq(test(x), true);
assertEq(test({}), true);
assertEq(test(null), true);
// ArrayBuffer's __proto__ behaviour verification.
var y = new ArrayBuffer();
y.__proto__ = null;
assertEq(y.__proto__, undefined);
reportCompare(true, true);

Просмотреть файл

@ -1,19 +0,0 @@
var x = new ArrayBuffer();
// first set to null should make the proto chain undefined
x.__proto__ = null;
assertEq(x.__proto__, undefined);
// second set makes it a property
x.__proto__ = null;
assertEq(x.__proto__, null);
// always act as a property now
x.__proto__ = {a:2};
assertEq(x.__proto__.a, 2);
assertEq(x.a, undefined);
var ab = new ArrayBuffer();
// not the same as setting __proto__ to null
ab.__proto__ = Object.create(null);
ab.__proto__ = {a:2};
// should still act like __proto__ is a plain property
assertEq(ab.a, undefined);
reportCompare(true, true);

Просмотреть файл

@ -206,6 +206,13 @@ GlobalObject::createArrayFromBuffer<uint8_clamped>() const
return createArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED);
}
void
GlobalObject::setProtoGetter(JSFunction *protoGetter)
{
JS_ASSERT(getSlotRef(PROTO_GETTER).isUndefined());
setSlot(PROTO_GETTER, ObjectValue(*protoGetter));
}
} // namespace js
#endif

Просмотреть файл

@ -10,6 +10,7 @@
#include "jscntxt.h"
#include "jsdate.h"
#include "jsexn.h"
#include "jsfriendapi.h"
#include "jsmath.h"
#include "json.h"
#include "jsweakmap.h"
@ -18,10 +19,10 @@
#include "builtin/MapObject.h"
#include "builtin/RegExp.h"
#include "frontend/BytecodeEmitter.h"
#include "vm/GlobalObject-inl.h"
#include "jsobjinlines.h"
#include "vm/GlobalObject-inl.h"
#include "vm/RegExpObject-inl.h"
#include "vm/RegExpStatics-inl.h"
@ -57,6 +58,121 @@ ThrowTypeError(JSContext *cx, unsigned argc, Value *vp)
namespace js {
static bool
TestProtoGetterThis(const Value &v)
{
return !v.isNullOrUndefined();
}
static bool
ProtoGetterImpl(JSContext *cx, CallArgs args)
{
JS_ASSERT(TestProtoGetterThis(args.thisv()));
const Value &thisv = args.thisv();
if (thisv.isPrimitive() && !BoxNonStrictThis(cx, args))
return false;
unsigned dummy;
Rooted<JSObject*> obj(cx, &args.thisv().toObject());
Rooted<jsid> nid(cx, NameToId(cx->runtime->atomState.protoAtom));
Rooted<Value> v(cx);
if (!CheckAccess(cx, obj, nid, JSACC_PROTO, v.address(), &dummy))
return false;
args.rval() = v;
return true;
}
static JSBool
ProtoGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod(cx, TestProtoGetterThis, ProtoGetterImpl, args);
}
size_t sSetProtoCalled = 0;
static bool
TestProtoSetterThis(const Value &v)
{
if (v.isNullOrUndefined())
return false;
/* These will work as if on a boxed primitive; dumb, but whatever. */
if (!v.isObject())
return true;
/* Otherwise, only accept non-proxies. */
return !v.toObject().isProxy();
}
static bool
ProtoSetterImpl(JSContext *cx, CallArgs args)
{
JS_ASSERT(TestProtoSetterThis(args.thisv()));
const Value &thisv = args.thisv();
if (thisv.isPrimitive()) {
JS_ASSERT(!thisv.isNullOrUndefined());
// Mutating a boxed primitive's [[Prototype]] has no side effects.
args.rval() = UndefinedValue();
return true;
}
if (!cx->runningWithTrustedPrincipals())
++sSetProtoCalled;
Rooted<JSObject*> obj(cx, &args.thisv().toObject());
/* ES5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */
if (!obj->isExtensible()) {
obj->reportNotExtensible(cx);
return false;
}
/*
* Disallow mutating the [[Prototype]] of a proxy that wasn't simply
* wrapping some other object. Also disallow it on ArrayBuffer objects,
* which due to their complicated delegate-object shenanigans can't easily
* have a mutable [[Prototype]].
*/
if (obj->isProxy() || obj->isArrayBuffer()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
"Object", "__proto__ setter",
obj->isProxy() ? "Proxy" : "ArrayBuffer");
return false;
}
/* Do nothing if __proto__ isn't being set to an object or null. */
if (args.length() == 0 || !args[0].isObjectOrNull()) {
args.rval() = UndefinedValue();
return true;
}
Rooted<JSObject*> newProto(cx, args[0].toObjectOrNull());
unsigned dummy;
Rooted<jsid> nid(cx, NameToId(cx->runtime->atomState.protoAtom));
Rooted<Value> v(cx);
if (!CheckAccess(cx, obj, nid, JSAccessMode(JSACC_PROTO | JSACC_WRITE), v.address(), &dummy))
return false;
if (!SetProto(cx, obj, newProto, true))
return false;
args.rval() = UndefinedValue();
return true;
}
static JSBool
ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod(cx, TestProtoSetterThis, ProtoSetterImpl, args);
}
JSObject *
GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
{
@ -184,8 +300,36 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
* primordial values have.
*/
if (!LinkConstructorAndPrototype(cx, objectCtor, objectProto) ||
!DefinePropertiesAndBrand(cx, objectProto, object_props, object_methods) ||
!DefinePropertiesAndBrand(cx, objectCtor, NULL, object_static_methods) ||
!DefinePropertiesAndBrand(cx, objectProto, NULL, object_methods))
{
return NULL;
}
/*
* Add an Object.prototype.__proto__ accessor property to implement that
* extension (if it's actually enabled). Cache the getter for this
* function so that cross-compartment [[Prototype]]-getting is implemented
* in one place.
*/
Rooted<JSFunction*> getter(cx, js_NewFunction(cx, NULL, ProtoGetter, 0, 0, self, NULL));
if (!getter)
return NULL;
#if JS_HAS_OBJ_PROTO_PROP
Rooted<JSFunction*> setter(cx, js_NewFunction(cx, NULL, ProtoSetter, 0, 0, self, NULL));
if (!setter)
return NULL;
if (!objectProto->defineProperty(cx, cx->runtime->atomState.protoAtom, UndefinedValue(),
JS_DATA_TO_FUNC_PTR(PropertyOp, getter.get()),
JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setter.get()),
JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))
{
return NULL;
}
#endif /* JS_HAS_OBJ_PROTO_PROP */
self->setProtoGetter(getter);
if (!DefinePropertiesAndBrand(cx, objectCtor, NULL, object_static_methods) ||
!LinkConstructorAndPrototype(cx, functionCtor, functionProto) ||
!DefinePropertiesAndBrand(cx, functionProto, NULL, function_methods) ||
!DefinePropertiesAndBrand(cx, functionCtor, NULL, NULL))
@ -315,14 +459,15 @@ GlobalObject::clear(JSContext *cx)
setSlot(RUNTIME_CODEGEN_ENABLED, UndefinedValue());
/*
* Clear all slots storing function values, in case throwing trying to
* execute a script for this global must reinitialize standard classes.
* See bug 470150.
* Clear all slots storing 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());
setSlot(PROTO_GETTER, UndefinedValue());
/*
* Mark global as cleared. If we try to execute any compile-and-go
@ -420,11 +565,14 @@ LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor_, JSObject *proto_)
}
bool
DefinePropertiesAndBrand(JSContext *cx, JSObject *obj_, JSPropertySpec *ps, JSFunctionSpec *fs)
DefinePropertiesAndBrand(JSContext *cx, JSObject *obj_,
const JSPropertySpec *ps, const JSFunctionSpec *fs)
{
RootedObject obj(cx, obj_);
if ((ps && !JS_DefineProperties(cx, obj, ps)) || (fs && !JS_DefineFunctions(cx, obj, fs)))
if (ps && !JS_DefineProperties(cx, obj, const_cast<JSPropertySpec*>(ps)))
return false;
if (fs && !JS_DefineFunctions(cx, obj, const_cast<JSFunctionSpec*>(fs)))
return false;
return true;
}

Просмотреть файл

@ -74,12 +74,13 @@ class GlobalObject : public JSObject
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;
static const unsigned PROTO_GETTER = THROWTYPEERROR + 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_UINT8 = PROTO_GETTER + 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;
@ -129,6 +130,7 @@ class GlobalObject : public JSObject
inline void setThrowTypeError(JSFunction *fun);
inline void setOriginalEval(JSObject *evalobj);
inline void setProtoGetter(JSFunction *protoGetter);
Value getConstructor(JSProtoKey key) const {
JS_ASSERT(key <= JSProto_LIMIT);
@ -347,6 +349,11 @@ class GlobalObject : public JSObject
template<typename T>
inline Value createArrayFromBuffer() const;
Value protoGetter() const {
JS_ASSERT(functionObjectClassesInitialized());
return getSlot(PROTO_GETTER);
}
void clear(JSContext *cx);
bool isCleared() const {
@ -395,7 +402,8 @@ LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto);
* benefits.
*/
extern bool
DefinePropertiesAndBrand(JSContext *cx, JSObject *obj, JSPropertySpec *ps, JSFunctionSpec *fs);
DefinePropertiesAndBrand(JSContext *cx, JSObject *obj,
const JSPropertySpec *ps, const JSFunctionSpec *fs);
typedef HashSet<GlobalObject *, DefaultHasher<GlobalObject *>, SystemAllocPolicy> GlobalObjectSet;