Bug 930414 - Replace |thisObject| object op with |thisValue| and use if for modules r=shu r=smaug

This commit is contained in:
Jon Coppeard 2015-10-21 10:21:44 +01:00
parent 59f519ac6f
commit 59be23d316
16 changed files with 91 additions and 97 deletions

View File

@ -3168,5 +3168,13 @@ DeprecationWarning(JSContext* aCx, JSObject* aObject,
}
}
bool
ObjectToOuterObjectValue(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp)
{
JSObject* outer = JS_ObjectToOuterObject(cx, obj);
vp.setObject(*outer);
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -789,6 +789,9 @@ TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
return true;
}
bool
ObjectToOuterObjectValue(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp);
// Make sure to wrap the given string value into the right compartment, as
// needed.
MOZ_ALWAYS_INLINE

View File

@ -453,7 +453,7 @@ class CGDOMJSClass(CGThing):
nullptr, /* unwatch */
nullptr, /* getElements */
nullptr, /* enumerate */
JS_ObjectToOuterObject /* thisObject */
mozilla::dom::ObjectToOuterObjectValue /* thisValue */
}
""",
objectMoved=objectMovedHook)

View File

@ -427,6 +427,9 @@ typedef bool
typedef bool
(* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
typedef bool
(* ThisValueOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
class JS_FRIEND_API(ElementAdder)
{
public:
@ -646,7 +649,7 @@ struct ObjectOps
UnwatchOp unwatch;
GetElementsOp getElements;
JSNewEnumerateOp enumerate;
ObjectOp thisObject;
ThisValueOp thisValue;
};
#define JS_NULL_OBJECT_OPS \

View File

@ -274,10 +274,8 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
MOZ_ASSERT(args.callee().global() == scopeobj->as<ClonedBlockObject>().global());
// Use the global as 'this', modulo outerization.
JSObject* thisobj = GetThisObject(cx, scopeobj);
if (!thisobj)
if (!GetThisValue(cx, scopeobj, &thisv))
return false;
thisv = ObjectValue(*thisobj);
}
RootedLinearString linearStr(cx, str->ensureLinear(cx));
@ -441,10 +439,8 @@ js::DirectEvalStringFromIon(JSContext* cx,
// value as necessary while it executes.
RootedValue nthisValue(cx, thisValue);
if (!callerScript->strict() && esg.script()->strict() && !thisValue.isObject()) {
JSObject* obj = BoxNonStrictThis(cx, thisValue);
if (!obj)
if (!BoxNonStrictThis(cx, thisValue, &nthisValue))
return false;
nthisValue = ObjectValue(*obj);
}
return ExecuteKernel(cx, esg.script(), *scopeobj, nthisValue, newTargetValue,
@ -520,11 +516,10 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
if (!scope)
return false;
JSObject* thisobj = GetThisObject(cx, global);
if (!thisobj)
RootedValue thisv(cx);
if (!GetThisValue(cx, global, &thisv))
return false;
RootedValue thisv(cx, ObjectValue(*thisobj));
RootedValue rval(cx);
if (!ExecuteKernel(cx, script, *scope, thisv, UndefinedValue(), EXECUTE_GLOBAL,
NullFramePtr() /* evalInFrame */, rval.address()))

View File

@ -943,13 +943,7 @@ static bool
DoThisFallback(JSContext* cx, ICThis_Fallback* stub, HandleValue thisv, MutableHandleValue ret)
{
FallbackICSpew(cx, stub, "This");
JSObject* thisObj = BoxNonStrictThis(cx, thisv);
if (!thisObj)
return false;
ret.setObject(*thisObj);
return true;
return BoxNonStrictThis(cx, thisv, ret);
}
typedef bool (*DoThisFallbackFn)(JSContext*, ICThis_Fallback*, HandleValue, MutableHandleValue);

View File

@ -5089,7 +5089,7 @@ CodeGenerator::visitReturnFromCtor(LReturnFromCtor* lir)
masm.bind(&end);
}
typedef JSObject* (*BoxNonStrictThisFn)(JSContext*, HandleValue);
typedef bool (*BoxNonStrictThisFn)(JSContext*, HandleValue, MutableHandleValue);
static const VMFunction BoxNonStrictThisInfo = FunctionInfo<BoxNonStrictThisFn>(BoxNonStrictThis);
void
@ -5098,13 +5098,11 @@ CodeGenerator::visitComputeThis(LComputeThis* lir)
ValueOperand value = ToValue(lir, LComputeThis::ValueIndex);
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, ArgList(value),
StoreRegisterTo(output));
OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, ArgList(value), StoreValueTo(value));
masm.branchTestObject(Assembler::NotEqual, value, ool->entry());
masm.unboxObject(value, output);
masm.bind(ool->rejoin());
masm.unboxObject(value, output);
}
void

View File

@ -1038,7 +1038,7 @@ GetObjectClassName(JSContext* cx, HandleObject obj);
/*
* Inner and outer objects
*
* GetInnerObject and GetOuterObject (and also GetThisObject, somewhat) have to
* GetInnerObject and GetOuterObject (and also GetThisValue, somewhat) have to
* do with Windows and WindowProxies. There's a screwy invariant that actual
* Window objects (the global objects of web pages) are never directly exposed
* to script. Instead we often substitute a WindowProxy.
@ -1078,7 +1078,7 @@ GetInnerObject(JSObject* obj)
*
* This must be called before passing an object to script, if the object might
* be a Window. (But usually those cases involve scope objects, and for those,
* it is better to call GetThisObject instead.)
* it is better to call GetThisValue instead.)
*/
inline JSObject*
GetOuterObject(JSContext* cx, HandleObject obj)
@ -1095,16 +1095,18 @@ GetOuterObject(JSContext* cx, HandleObject obj)
* Some JSObjects shouldn't be exposed directly to script. This includes (at
* least) DynamicWithObjects and Window objects. However, since both of those
* can be on scope chains, we sometimes would expose those as `this` if we
* were not so vigilant about calling GetThisObject where appropriate.
* were not so vigilant about calling GetThisValue where appropriate.
*
* See comments at ComputeImplicitThis.
*/
inline JSObject*
GetThisObject(JSContext* cx, HandleObject obj)
inline bool
GetThisValue(JSContext* cx, HandleObject obj, MutableHandleValue vp)
{
if (ObjectOp op = obj->getOps()->thisObject)
return op(cx, obj);
return obj;
if (ThisValueOp op = obj->getOps()->thisValue)
return op(cx, obj, vp);
vp.setObject(*obj);
return true;
}

View File

@ -6715,10 +6715,8 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code
* object, it should have a thisObject hook that returns the
* appropriate outer object.
*/
JSObject* thisObj = GetThisObject(cx, scope);
if (!thisObj)
if (!GetThisValue(cx, scope, &thisv))
return false;
thisv = ObjectValue(*thisObj);
env = scope;
}

View File

@ -63,11 +63,11 @@ ComputeThis(JSContext* cx, AbstractFramePtr frame)
MOZ_ASSERT_IF(frame.isEvalFrame(), thisv.isUndefined() || thisv.isNull());
}
JSObject* thisObj = BoxNonStrictThis(cx, thisv);
if (!thisObj)
RootedValue result(cx);
if (!BoxNonStrictThis(cx, thisv, &result))
return false;
frame.thisValue().setObject(*thisObj);
frame.thisValue() = result;
return true;
}

View File

@ -84,8 +84,8 @@ LooseEqualityOp(JSContext* cx, InterpreterRegs& regs)
return true;
}
JSObject*
js::BoxNonStrictThis(JSContext* cx, HandleValue thisv)
bool
js::BoxNonStrictThis(JSContext* cx, HandleValue thisv, MutableHandleValue vp)
{
/*
* Check for SynthesizeFrame poisoning and fast constructors which
@ -95,13 +95,16 @@ js::BoxNonStrictThis(JSContext* cx, HandleValue thisv)
if (thisv.isNullOrUndefined()) {
Rooted<GlobalObject*> global(cx, cx->global());
return GetThisObject(cx, global);
return GetThisValue(cx, global, vp);
}
if (thisv.isObject())
return &thisv.toObject();
if (thisv.isObject()) {
vp.set(thisv);
return true;
}
return PrimitiveToObject(cx, thisv);
vp.setObject(*PrimitiveToObject(cx, thisv));
return true;
}
/*
@ -133,12 +136,7 @@ js::BoxNonStrictThis(JSContext* cx, const CallReceiver& call)
MOZ_ASSERT_IF(fun && fun->isInterpreted(), !fun->strict());
#endif
JSObject* thisObj = BoxNonStrictThis(cx, call.thisv());
if (!thisObj)
return false;
call.setThis(ObjectValue(*thisObj));
return true;
return BoxNonStrictThis(cx, call.thisv(), call.mutableThisv());
}
#if JS_HAS_NO_SUCH_METHOD
@ -829,10 +827,8 @@ js::Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc,
fval.toObject().as<JSFunction>().jitInfo()->needsOuterizedThisObject())
{
RootedObject thisObj(cx, &args.thisv().toObject());
JSObject* thisp = GetThisObject(cx, thisObj);
if (!thisp)
if (!GetThisValue(cx, thisObj, args.mutableThisv()))
return false;
args.setThis(ObjectValue(*thisp));
}
}
@ -1029,20 +1025,11 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
} while ((s = s->enclosingScope()));
#endif
ExecuteType type;
Value thisv;
if (script->module()) {
type = EXECUTE_MODULE;
thisv = UndefinedValue();
} else {
type = EXECUTE_GLOBAL;
ExecuteType type = script->module() ? EXECUTE_MODULE : EXECUTE_GLOBAL;
/* Use the scope chain as 'this', modulo outerization. */
JSObject* thisObj = GetThisObject(cx, scopeChain);
if (!thisObj)
return false;
thisv = ObjectValue(*thisObj);
}
RootedValue thisv(cx);
if (!GetThisValue(cx, scopeChain, &thisv))
return false;
return ExecuteKernel(cx, script, *scopeChain, thisv, NullValue(), type,
NullFramePtr() /* evalInFrame */, rval);
@ -1609,7 +1596,7 @@ JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
* is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
* censored with undefined.
*
* Otherwise, we bind |this| to GetThisObject(cx, obj). Only names inside
* Otherwise, we bind |this| to the result of GetThisValue(). Only names inside
* |with| statements and embedding-specific scope objects fall into this
* category.
*
@ -1632,12 +1619,7 @@ ComputeImplicitThis(JSContext* cx, HandleObject obj, MutableHandleValue vp)
if (IsCacheableNonGlobalScope(obj))
return true;
JSObject* nobj = GetThisObject(cx, obj);
if (!nobj)
return false;
vp.setObject(*nobj);
return true;
return GetThisValue(cx, obj, vp);
}
static MOZ_ALWAYS_INLINE bool

View File

@ -31,8 +31,8 @@ class ScopeIter;
extern bool
BoxNonStrictThis(JSContext* cx, const CallReceiver& call);
extern JSObject*
BoxNonStrictThis(JSContext* cx, HandleValue thisv);
extern bool
BoxNonStrictThis(JSContext* cx, HandleValue thisv, MutableHandleValue vp);
/*
* Ensure that fp->thisValue() is the correct value of |this| for the scripted

View File

@ -344,7 +344,7 @@ const Class ModuleEnvironmentObject::class_ = {
nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
ModuleEnvironmentObject::enumerate,
nullptr /* thisObject */
ModuleEnvironmentObject::thisValue
}
};
@ -519,6 +519,13 @@ ModuleEnvironmentObject::enumerate(JSContext* cx, HandleObject obj, AutoIdVector
return true;
}
/* static */ bool
ModuleEnvironmentObject::thisValue(JSContext* cx, HandleObject obj, MutableHandleValue vp)
{
vp.setUndefined();
return true;
}
/*****************************************************************************/
const Class DeclEnvObject::class_ = {
@ -626,13 +633,13 @@ DynamicWithObject::create(JSContext* cx, HandleObject object, HandleObject enclo
if (!obj)
return nullptr;
JSObject* thisp = GetThisObject(cx, object);
if (!thisp)
RootedValue thisv(cx);
if (!GetThisValue(cx, object, &thisv))
return nullptr;
obj->setEnclosingScope(enclosing);
obj->setFixedSlot(OBJECT_SLOT, ObjectValue(*object));
obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
obj->setFixedSlot(THIS_SLOT, thisv);
obj->setFixedSlot(KIND_SLOT, Int32Value(kind));
return obj;
@ -698,10 +705,11 @@ with_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult
return DeleteProperty(cx, actual, id, result);
}
static JSObject*
with_ThisObject(JSContext* cx, HandleObject obj)
static bool
with_ThisValue(JSContext* cx, HandleObject obj, MutableHandleValue vp)
{
return &obj->as<DynamicWithObject>().withThis();
vp.set(obj->as<DynamicWithObject>().withThis());
return true;
}
const Class StaticWithObject::class_ = {
@ -739,7 +747,7 @@ const Class DynamicWithObject::class_ = {
nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
with_ThisObject,
with_ThisValue,
}
};
@ -1005,8 +1013,8 @@ StaticBlockObject::addVar(ExclusiveContext* cx, Handle<StaticBlockObject*> block
/* allowDictionary = */ false);
}
static JSObject*
block_ThisObject(JSContext* cx, HandleObject obj)
static bool
block_ThisValue(JSContext* cx, HandleObject obj, MutableHandleValue vp)
{
// No other block objects should ever get passed to the 'this' object
// hook except the global lexical scope and non-syntactic ones.
@ -1015,7 +1023,7 @@ block_ThisObject(JSContext* cx, HandleObject obj)
MOZ_ASSERT_IF(obj->as<ClonedBlockObject>().isGlobal(),
obj->enclosingScope() == cx->global());
RootedObject enclosing(cx, obj->enclosingScope());
return GetThisObject(cx, enclosing);
return GetThisValue(cx, enclosing, vp);
}
const Class BlockObject::class_ = {
@ -1047,7 +1055,7 @@ const Class BlockObject::class_ = {
nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
block_ThisObject,
block_ThisValue,
}
};

View File

@ -403,6 +403,7 @@ class ModuleEnvironmentObject : public CallObject
ObjectOpResult& result);
static bool enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly);
static bool thisValue(JSContext* cx, HandleObject obj, MutableHandleValue vp);
};
typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
@ -676,8 +677,10 @@ class DynamicWithObject : public NestedScopeObject
}
/* Return object for the 'this' class hook. */
JSObject& withThis() const {
return getReservedSlot(THIS_SLOT).toObject();
Value withThis() const {
Value thisValue = getReservedSlot(THIS_SLOT);
MOZ_ASSERT(thisValue.isObject());
return thisValue;
}
/*

View File

@ -665,7 +665,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = {
nullptr, nullptr, // watch/unwatch
nullptr, // getElements
nullptr, // enumerate
XPC_WN_JSOp_ThisObject,
XPC_WN_JSOp_ThisValue,
}
}
};
@ -927,10 +927,10 @@ XPC_WN_JSOp_Enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
return retval;
}
JSObject*
XPC_WN_JSOp_ThisObject(JSContext* cx, HandleObject obj)
bool
XPC_WN_JSOp_ThisValue(JSContext* cx, HandleObject obj, MutableHandleValue vp)
{
return JS_ObjectToOuterObject(cx, obj);
return mozilla::dom::ObjectToOuterObjectValue(cx, obj, vp);
}
/***************************************************************************/
@ -1036,7 +1036,7 @@ XPCNativeScriptableShared::PopulateJSClass()
js::ObjectOps* ops = &mJSClass.base.ops;
if (mFlags.WantNewEnumerate())
ops->enumerate = XPC_WN_JSOp_Enumerate;
ops->thisObject = XPC_WN_JSOp_ThisObject;
ops->thisValue = XPC_WN_JSOp_ThisValue;
if (mFlags.WantCall())

View File

@ -944,8 +944,8 @@ XPC_WN_CallMethod(JSContext* cx, unsigned argc, JS::Value* vp);
extern bool
XPC_WN_GetterSetter(JSContext* cx, unsigned argc, JS::Value* vp);
extern JSObject*
XPC_WN_JSOp_ThisObject(JSContext* cx, JS::HandleObject obj);
extern bool
XPC_WN_JSOp_ThisValue(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
// Macros to initialize Object or Function like XPC_WN classes
#define XPC_WN_WithCall_ObjectOps \
@ -960,7 +960,7 @@ XPC_WN_JSOp_ThisObject(JSContext* cx, JS::HandleObject obj);
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* getElements */ \
nullptr, /* enumerate */ \
XPC_WN_JSOp_ThisObject, \
XPC_WN_JSOp_ThisValue, \
}
#define XPC_WN_NoCall_ObjectOps \
@ -975,7 +975,7 @@ XPC_WN_JSOp_ThisObject(JSContext* cx, JS::HandleObject obj);
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* getElements */ \
nullptr, /* enumerate */ \
XPC_WN_JSOp_ThisObject, \
XPC_WN_JSOp_ThisValue, \
}
// Maybe this macro should check for class->enumerate ==