Bug 889543 - Use AutoCycleDetector instead of CloneMemory; r=till

--HG--
extra : rebase_source : 394255ac2da12eaea09c8be95847a5d19f6b3b21
This commit is contained in:
Terrence Cole 2014-03-11 09:00:16 -07:00
parent 92c7a79f42
commit d01e2ab502

View File

@ -970,25 +970,20 @@ JSRuntime::isSelfHostingCompartment(JSCompartment *comp)
return selfHostingGlobal_->compartment() == comp; return selfHostingGlobal_->compartment() == comp;
} }
// CloneMemory maps objects to each other which may be in different static bool
// runtimes. This class should only be used within an AutoSuppressGC, CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp);
// so that issues of managing which objects should be traced can be ignored.
typedef HashMap<JSObject *, JSObject *> CloneMemory;
static bool static bool
CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects); GetUnclonedValue(JSContext *cx, HandleObject selfHostedObject, HandleId id, MutableHandleValue vp)
static bool
GetUnclonedValue(JSContext *cx, JSObject *selfHostedObject, jsid id, Value *vp)
{ {
*vp = UndefinedValue(); vp.setUndefined();
if (JSID_IS_INT(id)) { if (JSID_IS_INT(id)) {
size_t index = JSID_TO_INT(id); size_t index = JSID_TO_INT(id);
if (index < selfHostedObject->getDenseInitializedLength() && if (index < selfHostedObject->getDenseInitializedLength() &&
!selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE)) !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
{ {
*vp = selfHostedObject->getDenseElement(JSID_TO_INT(id)); vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id)));
return true; return true;
} }
} }
@ -999,30 +994,27 @@ GetUnclonedValue(JSContext *cx, JSObject *selfHostedObject, jsid id, Value *vp)
// hosted global which aren't present. // hosted global which aren't present.
if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) { if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
JS_ASSERT(selfHostedObject->is<GlobalObject>()); JS_ASSERT(selfHostedObject->is<GlobalObject>());
gc::AutoSuppressGC suppress(cx);
RootedValue value(cx, IdToValue(id)); RootedValue value(cx, IdToValue(id));
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP, return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr); JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
} }
Shape *shape = selfHostedObject->nativeLookupPure(id); RootedShape shape(cx, selfHostedObject->nativeLookupPure(id));
if (!shape) { if (!shape) {
gc::AutoSuppressGC suppress(cx);
RootedValue value(cx, IdToValue(id)); RootedValue value(cx, IdToValue(id));
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP, return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr); JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
} }
JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter()); JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
*vp = selfHostedObject->getSlot(shape->slot()); vp.set(selfHostedObject->getSlot(shape->slot()));
return true; return true;
} }
static bool static bool
CloneProperties(JSContext *cx, JSObject *selfHostedObject, CloneProperties(JSContext *cx, HandleObject selfHostedObject, HandleObject clone)
HandleObject clone, CloneMemory &clonedObjects)
{ {
Vector<jsid> ids(cx); AutoIdVector ids(cx);
for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) { for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) { if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
@ -1039,12 +1031,12 @@ CloneProperties(JSContext *cx, JSObject *selfHostedObject,
RootedId id(cx); RootedId id(cx);
RootedValue val(cx); RootedValue val(cx);
RootedValue selfHostedValue(cx);
for (uint32_t i = 0; i < ids.length(); i++) { for (uint32_t i = 0; i < ids.length(); i++) {
id = ids[i]; id = ids[i];
Value selfHostedValue;
if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue)) if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
return false; return false;
if (!CloneValue(cx, selfHostedValue, &val, clonedObjects) || if (!CloneValue(cx, selfHostedValue, &val) ||
!JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0)) !JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0))
{ {
return false; return false;
@ -1055,20 +1047,24 @@ CloneProperties(JSContext *cx, JSObject *selfHostedObject,
} }
static JSObject * static JSObject *
CloneObject(JSContext *cx, JSObject *selfHostedObject, CloneMemory &clonedObjects) CloneObject(JSContext *cx, HandleObject selfHostedObject)
{ {
DependentAddPtr<CloneMemory> p(cx, clonedObjects, selfHostedObject); AutoCycleDetector detect(cx, selfHostedObject);
if (p) if (!detect.init())
return p->value(); return nullptr;
if (detect.foundCycle()) {
JS_ReportError(cx, "SelfHosted cloning cannot handle cyclic object graphs.");
return nullptr;
}
RootedObject clone(cx); RootedObject clone(cx);
if (selfHostedObject->is<JSFunction>()) { if (selfHostedObject->is<JSFunction>()) {
JSFunction *selfHostedFunction = &selfHostedObject->as<JSFunction>(); RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
bool hasName = selfHostedFunction->atom() != nullptr; bool hasName = selfHostedFunction->atom() != nullptr;
js::gc::AllocKind kind = hasName js::gc::AllocKind kind = hasName
? JSFunction::ExtendedFinalizeKind ? JSFunction::ExtendedFinalizeKind
: selfHostedFunction->getAllocKind(); : selfHostedFunction->getAllocKind();
clone = CloneFunctionObject(cx, HandleFunction::fromMarkedLocation(&selfHostedFunction), clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject);
cx->global(), kind, TenuredObject);
// To be able to re-lazify the cloned function, its name in the // To be able to re-lazify the cloned function, its name in the
// self-hosting compartment has to be stored on the clone. // self-hosting compartment has to be stored on the clone.
if (clone && hasName) if (clone && hasName)
@ -1104,21 +1100,17 @@ CloneObject(JSContext *cx, JSObject *selfHostedObject, CloneMemory &clonedObject
} }
if (!clone) if (!clone)
return nullptr; return nullptr;
if (!p.add(cx, clonedObjects, selfHostedObject, clone)) if (!CloneProperties(cx, selfHostedObject, clone))
return nullptr; return nullptr;
if (!CloneProperties(cx, selfHostedObject, clone, clonedObjects)) {
clonedObjects.remove(selfHostedObject);
return nullptr;
}
return clone; return clone;
} }
static bool static bool
CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects) CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp)
{ {
if (selfHostedValue.isObject()) { if (selfHostedValue.isObject()) {
JSObject *selfHostedObject = &selfHostedValue.toObject(); RootedObject selfHostedObject(cx, &selfHostedValue.toObject());
RootedObject clone(cx, CloneObject(cx, selfHostedObject, clonedObjects)); JSObject *clone = CloneObject(cx, selfHostedObject);
if (!clone) if (!clone)
return false; return false;
vp.setObject(*clone); vp.setObject(*clone);
@ -1129,25 +1121,25 @@ CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, C
if (!selfHostedValue.toString()->isFlat()) if (!selfHostedValue.toString()->isFlat())
MOZ_CRASH(); MOZ_CRASH();
JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat(); JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
RootedString clone(cx, js_NewStringCopyN<CanGC>(cx, JSString *clone = js_NewStringCopyN<CanGC>(cx,
selfHostedString->chars(), selfHostedString->chars(),
selfHostedString->length())); selfHostedString->length());
if (!clone) if (!clone)
return false; return false;
vp.setString(clone); vp.setString(clone);
} else { } else {
MOZ_ASSUME_UNREACHABLE("Self-hosting CloneValue can't clone given value."); MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
} }
return true; return true;
} }
bool bool
JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> name, JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, HandlePropertyName name,
Handle<JSFunction*> targetFun) HandleFunction targetFun)
{ {
RootedId id(cx, NameToId(name)); RootedId id(cx, NameToId(name));
Value funVal; RootedValue funVal(cx);
if (!GetUnclonedValue(cx, selfHostingGlobal_, id, &funVal)) if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &funVal))
return false; return false;
RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>()); RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
@ -1173,11 +1165,11 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> na
} }
bool bool
JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, MutableHandleValue vp) JSRuntime::cloneSelfHostedValue(JSContext *cx, HandlePropertyName name, MutableHandleValue vp)
{ {
RootedId id(cx, NameToId(name)); RootedId id(cx, NameToId(name));
Value selfHostedValue; RootedValue selfHostedValue(cx);
if (!GetUnclonedValue(cx, selfHostingGlobal_, id, &selfHostedValue)) if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue))
return false; return false;
/* /*
@ -1185,15 +1177,12 @@ JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, Mutab
* means we're currently executing the self-hosting script while * means we're currently executing the self-hosting script while
* initializing the runtime (see JSRuntime::initSelfHosting). * initializing the runtime (see JSRuntime::initSelfHosting).
*/ */
if (cx->global() != selfHostingGlobal_) { if (cx->global() == selfHostingGlobal_) {
gc::AutoSuppressGC suppress(cx);
CloneMemory clonedObjects(cx);
if (!clonedObjects.init() || !CloneValue(cx, selfHostedValue, vp, clonedObjects))
return false;
} else {
vp.set(selfHostedValue); vp.set(selfHostedValue);
return true;
} }
return true;
return CloneValue(cx, selfHostedValue, vp);
} }
JSFunction * JSFunction *