static JSObject * CloneObject(JSContext *cx, HandleObject selfHostedObject) { AutoCycleDetector detect(cx, selfHostedObject); if (!detect.init()) return nullptr; if (detect.foundCycle()) { JS_ReportError(cx, "SelfHosted cloning cannot handle cyclic object graphs."); return nullptr; } RootedObject clone(cx); if (selfHostedObject->is<JSFunction>()) { RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>()); bool hasName = selfHostedFunction->atom() != nullptr; // Arrow functions use the first extended slot for their lexical |this| value. JS_ASSERT(!selfHostedFunction->isArrow()); js::gc::AllocKind kind = hasName ? JSFunction::ExtendedFinalizeKind : selfHostedFunction->getAllocKind(); clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject); // To be able to re-lazify the cloned function, its name in the // self-hosting compartment has to be stored on the clone. if (clone && hasName) clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom())); } else if (selfHostedObject->is<RegExpObject>()) { RegExpObject &reobj = selfHostedObject->as<RegExpObject>(); RootedAtom source(cx, reobj.getSource()); JS_ASSERT(source->isPermanentAtom()); clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr); } else if (selfHostedObject->is<DateObject>()) { clone = JS_NewDateObjectMsec(cx, selfHostedObject->as<DateObject>().UTCTime().toNumber()); } else if (selfHostedObject->is<BooleanObject>()) { clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox()); } else if (selfHostedObject->is<NumberObject>()) { clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox()); } else if (selfHostedObject->is<StringObject>()) { JSString *selfHostedString = selfHostedObject->as<StringObject>().unbox(); if (!selfHostedString->isFlat()) MOZ_CRASH(); RootedString str(cx, js_NewStringCopyN<CanGC>(cx, selfHostedString->asFlat().chars(), selfHostedString->asFlat().length())); if (!str) return nullptr; clone = StringObject::create(cx, str); } else if (selfHostedObject->is<ArrayObject>()) { clone = NewDenseEmptyArray(cx, nullptr, TenuredObject); } else { JS_ASSERT(selfHostedObject->isNative()); clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr, cx->global(), selfHostedObject->tenuredGetAllocKind(), SingletonObject); } if (!clone) return nullptr; if (!CloneProperties(cx, selfHostedObject, clone)) return nullptr; return clone; }
static JSObject * CloneObject(JSContext *cx, JSObject *selfHostedObject, CloneMemory &clonedObjects) { DependentAddPtr<CloneMemory> p(cx, clonedObjects, selfHostedObject); if (p) return p->value(); RootedObject clone(cx); if (selfHostedObject->is<JSFunction>()) { JSFunction *selfHostedFunction = &selfHostedObject->as<JSFunction>(); bool hasName = selfHostedFunction->atom() != nullptr; js::gc::AllocKind kind = hasName ? JSFunction::ExtendedFinalizeKind : selfHostedFunction->getAllocKind(); clone = CloneFunctionObject(cx, HandleFunction::fromMarkedLocation(&selfHostedFunction), cx->global(), kind, TenuredObject); // To be able to re-lazify the cloned function, its name in the // self-hosting compartment has to be stored on the clone. if (clone && hasName) clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom())); } else if (selfHostedObject->is<RegExpObject>()) { RegExpObject &reobj = selfHostedObject->as<RegExpObject>(); RootedAtom source(cx, reobj.getSource()); JS_ASSERT(source->isPermanentAtom()); clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr); } else if (selfHostedObject->is<DateObject>()) { clone = JS_NewDateObjectMsec(cx, selfHostedObject->as<DateObject>().UTCTime().toNumber()); } else if (selfHostedObject->is<BooleanObject>()) { clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox()); } else if (selfHostedObject->is<NumberObject>()) { clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox()); } else if (selfHostedObject->is<StringObject>()) { JSString *selfHostedString = selfHostedObject->as<StringObject>().unbox(); if (!selfHostedString->isFlat()) MOZ_CRASH(); RootedString str(cx, js_NewStringCopyN<CanGC>(cx, selfHostedString->asFlat().chars(), selfHostedString->asFlat().length())); if (!str) return nullptr; clone = StringObject::create(cx, str); } else if (selfHostedObject->is<ArrayObject>()) { clone = NewDenseEmptyArray(cx, nullptr, TenuredObject); } else { JS_ASSERT(selfHostedObject->isNative()); clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr, cx->global(), selfHostedObject->tenuredGetAllocKind(), SingletonObject); } if (!clone) return nullptr; if (!p.add(cx, clonedObjects, selfHostedObject, clone)) return nullptr; if (!CloneProperties(cx, selfHostedObject, clone, clonedObjects)) { clonedObjects.remove(selfHostedObject); return nullptr; } return clone; }