Bug 1271653 - Implement a C++ function for makeDebuggeeValue/unsafeDereference/unwrap;r=jimb

This commit is contained in:
Eddy Bruel 2016-06-06 14:07:58 +02:00
Родитель 77c9eba63e
Коммит 97e08ffec4
2 изменённых файлов: 143 добавлений и 83 удалений

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

@ -1080,41 +1080,10 @@ Debugger::wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp)
if (vp.isObject()) {
RootedObject obj(cx, &vp.toObject());
if (obj->is<JSFunction>()) {
MOZ_ASSERT(!IsInternalFunctionObject(*obj));
RootedFunction fun(cx, &obj->as<JSFunction>());
if (!EnsureFunctionHasScript(cx, fun))
return false;
}
if (!wrapDebuggeeObject(cx, &obj))
return false;
DependentAddPtr<ObjectWeakMap> p(cx, objects, obj);
if (p) {
vp.setObject(*p->value());
} else {
/* Create a new Debugger.Object for obj. */
RootedNativeObject debugger(cx, object);
RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_OBJECT_PROTO).toObject());
NativeObject* dobj = DebuggerObject::create(cx, proto, obj, debugger);
if (!dobj)
return false;
if (!p.add(cx, objects, obj, dobj)) {
NukeDebuggerWrapper(dobj);
return false;
}
if (obj->compartment() != object->compartment()) {
CrossCompartmentKey key(object, obj, CrossCompartmentKey::DebuggerObject);
if (!object->compartment()->putWrapper(cx, key, ObjectValue(*dobj))) {
NukeDebuggerWrapper(dobj);
objects.remove(obj);
ReportOutOfMemory(cx);
return false;
}
}
vp.setObject(*dobj);
}
vp.setObject(*obj);
} else if (vp.isMagic()) {
RootedPlainObject optObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!optObj)
@ -1146,6 +1115,48 @@ Debugger::wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp)
return true;
}
bool
Debugger::wrapDebuggeeObject(JSContext* cx, MutableHandleObject obj)
{
if (obj->is<JSFunction>()) {
MOZ_ASSERT(!IsInternalFunctionObject(*obj));
RootedFunction fun(cx, &obj->as<JSFunction>());
if (!EnsureFunctionHasScript(cx, fun))
return false;
}
DependentAddPtr<ObjectWeakMap> p(cx, objects, obj);
if (p) {
obj.set(p->value());
} else {
/* Create a new Debugger.Object for obj. */
RootedNativeObject debugger(cx, object);
RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_OBJECT_PROTO).toObject());
NativeObject* dobj = DebuggerObject::create(cx, proto, obj, debugger);
if (!dobj)
return false;
if (!p.add(cx, objects, obj, dobj)) {
NukeDebuggerWrapper(dobj);
return false;
}
if (obj->compartment() != object->compartment()) {
CrossCompartmentKey key(object, obj, CrossCompartmentKey::DebuggerObject);
if (!object->compartment()->putWrapper(cx, key, ObjectValue(*dobj))) {
NukeDebuggerWrapper(dobj);
objects.remove(obj);
ReportOutOfMemory(cx);
return false;
}
}
obj.set(dobj);
}
return true;
}
static NativeObject*
ToNativeDebuggerObject(JSContext* cx, MutableHandleObject obj)
{
@ -8712,69 +8723,36 @@ DebuggerObject_executeInGlobalWithBindings(JSContext* cx, unsigned argc, Value*
static bool
DebuggerObject_makeDebuggeeValue(JSContext* cx, unsigned argc, Value* vp)
{
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "makeDebuggeeValue", args, dbg, referent);
THIS_DEBUGOBJECT(cx, argc, vp, "makeDebuggeeValue", args, object);
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.makeDebuggeeValue", 1))
return false;
RootedValue arg0(cx, args[0]);
return DebuggerObject::makeDebuggeeValue(cx, object, args[0], args.rval());
}
/* Non-objects are already debuggee values. */
if (arg0.isObject()) {
// Enter this Debugger.Object's referent's compartment, and wrap the
// argument as appropriate for references from there.
{
AutoCompartment ac(cx, referent);
if (!cx->compartment()->wrap(cx, &arg0))
return false;
}
static bool
DebuggerObject_unsafeDereference(JSContext* cx, unsigned argc, Value* vp)
{
THIS_DEBUGOBJECT(cx, argc, vp, "unsafeDereference", args, object);
// Back in the debugger's compartment, produce a new Debugger.Object
// instance referring to the wrapped argument.
if (!dbg->wrapDebuggeeValue(cx, &arg0))
return false;
}
RootedObject result(cx);
if (!DebuggerObject::unsafeDereference(cx, object, &result))
return false;
args.rval().set(arg0);
args.rval().setObject(*result);
return true;
}
static bool
DebuggerObject_unwrap(JSContext* cx, unsigned argc, Value* vp)
{
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "unwrap", args, dbg, referent);
JSObject* unwrapped = UnwrapOneChecked(referent);
if (!unwrapped) {
args.rval().setNull();
return true;
}
THIS_DEBUGOBJECT(cx, argc, vp, "unwrap", args, object);
// Don't allow unwrapping to create a D.O whose referent is in an
// invisible-to-Debugger global. (If our referent is a *wrapper* to such,
// and the wrapper is in a visible compartment, that's fine.)
JSCompartment* unwrappedCompartment = unwrapped->compartment();
if (unwrappedCompartment->creationOptions().invisibleToDebugger()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_INVISIBLE_COMPARTMENT);
return false;
}
args.rval().setObject(*unwrapped);
if (!dbg->wrapDebuggeeValue(cx, args.rval()))
return false;
return true;
}
static bool
DebuggerObject_unsafeDereference(JSContext* cx, unsigned argc, Value* vp)
{
THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "unsafeDereference", args, referent);
args.rval().setObject(*referent);
if (!cx->compartment()->wrap(cx, args.rval()))
Rooted<DebuggerObject*> result(cx);
if (!DebuggerObject::unwrap(cx, object, &result))
return false;
// Wrapping should return the WindowProxy.
MOZ_ASSERT(!IsWindow(&args.rval().toObject()));
args.rval().setObjectOrNull(result);
return true;
}
@ -8832,8 +8810,8 @@ const JSFunctionSpec DebuggerObject::methods_[] = {
JS_FN("executeInGlobal", DebuggerObject_executeInGlobal, 1, 0),
JS_FN("executeInGlobalWithBindings", DebuggerObject_executeInGlobalWithBindings, 2, 0),
JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
JS_FN("unsafeDereference", DebuggerObject_unsafeDereference, 0, 0),
JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
JS_FS_END
};
@ -9216,6 +9194,81 @@ DebuggerObject::executeInGlobal(JSContext* cx, Handle<DebuggerObject*> object,
nullptr);
}
/* static */ bool
DebuggerObject::makeDebuggeeValue(JSContext* cx, Handle<DebuggerObject*> object,
HandleValue value_, MutableHandleValue result)
{
RootedObject referent(cx, object->referent());
Debugger* dbg = object->owner();
RootedValue value(cx, value_);
/* Non-objects are already debuggee values. */
if (value.isObject()) {
// Enter this Debugger.Object's referent's compartment, and wrap the
// argument as appropriate for references from there.
{
AutoCompartment ac(cx, referent);
if (!cx->compartment()->wrap(cx, &value))
return false;
}
// Back in the debugger's compartment, produce a new Debugger.Object
// instance referring to the wrapped argument.
if (!dbg->wrapDebuggeeValue(cx, &value))
return false;
}
result.set(value);
return true;
}
/* static */ bool
DebuggerObject::unsafeDereference(JSContext* cx, Handle<DebuggerObject*> object,
MutableHandleObject result)
{
RootedObject referent(cx, object->referent());
if (!cx->compartment()->wrap(cx, &referent))
return false;
// Wrapping should return the WindowProxy.
MOZ_ASSERT(!IsWindow(referent));
result.set(referent);
return true;
}
/* static */ bool
DebuggerObject::unwrap(JSContext* cx, Handle<DebuggerObject*> object,
MutableHandle<DebuggerObject*> result)
{
RootedObject referent(cx, object->referent());
Debugger* dbg = object->owner();
RootedObject unwrapped(cx, UnwrapOneChecked(referent));
if (!unwrapped) {
result.set(nullptr);
return true;
}
// Don't allow unwrapping to create a D.O whose referent is in an
// invisible-to-Debugger global. (If our referent is a *wrapper* to such,
// and the wrapper is in a visible compartment, that's fine.)
JSCompartment* unwrappedCompartment = unwrapped->compartment();
if (unwrappedCompartment->creationOptions().invisibleToDebugger()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_INVISIBLE_COMPARTMENT);
return false;
}
if (!dbg->wrapDebuggeeObject(cx, &unwrapped))
return false;
result.set(&unwrapped->as<DebuggerObject>());
return true;
}
/* static */ bool
DebuggerObject::requireGlobalObject(JSContext* cx, Handle<DebuggerObject*> object)
{

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

@ -917,6 +917,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
* form { uninitialized: true }.
*/
bool wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp);
bool wrapDebuggeeObject(JSContext* cx, MutableHandleObject obj);
/*
* Unwrap a Debug.Object, without rewrapping it for any particular debuggee
@ -1076,6 +1077,12 @@ class DebuggerObject : public NativeObject
static bool executeInGlobal(JSContext* cx, Handle<DebuggerObject*> object,
mozilla::Range<const char16_t> chars, HandleObject bindings,
const EvalOptions& options, MutableHandleValue result);
static bool makeDebuggeeValue(JSContext* cx, Handle<DebuggerObject*> object,
HandleValue value, MutableHandleValue result);
static bool unsafeDereference(JSContext* cx, Handle<DebuggerObject*> object,
MutableHandleObject result);
static bool unwrap(JSContext* cx, Handle<DebuggerObject*> object,
MutableHandle<DebuggerObject*> result);
private:
enum {