FRAGMENT(JSObject, simple) { JS::Rooted<JSObject*> glob(cx, JS::CurrentGlobalOrNull(cx)); JS::Rooted<JSObject*> plain(cx, JS_NewPlainObject(cx)); JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx)); JS::Rooted<JSObject*> func(cx, (JSObject*) JS_NewFunction(cx, (JSNative) 1, 0, 0, global, "dys")); JS::Rooted<JSObject*> anon(cx, (JSObject*) JS_NewFunction(cx, (JSNative) 1, 0, 0, global, 0)); JS::Rooted<JSFunction*> funcPtr(cx, JS_NewFunction(cx, (JSNative) 1, 0, 0, global, "formFollows")); JSObject& plainRef = *plain; JSFunction& funcRef = *funcPtr; JSObject* plainRaw = plain; JSObject* funcRaw = func; breakpoint(); (void) glob; (void) plain; (void) func; (void) anon; (void) funcPtr; (void) &plainRef; (void) &funcRef; (void) plainRaw; (void) funcRaw; }
bool ReflectIceEntry(const WebrtcTelemetry::WebrtcIceCandidateType *entry, const WebrtcTelemetry::WebrtcIceCandidateStats *stat, JSContext *cx, JS::Handle<JSObject*> obj) { if ((stat->successCount == 0) && (stat->failureCount == 0)) return true; const uint32_t &bitmask = entry->GetKey(); JS::Rooted<JSObject*> statsObj(cx, JS_NewPlainObject(cx)); if (!statsObj) return false; if (!JS_DefineProperty(cx, obj, nsPrintfCString("%lu", bitmask).BeginReading(), statsObj, JSPROP_ENUMERATE)) { return false; } if (stat->successCount && !JS_DefineProperty(cx, statsObj, "successCount", stat->successCount, JSPROP_ENUMERATE)) { return false; } if (stat->failureCount && !JS_DefineProperty(cx, statsObj, "failureCount", stat->failureCount, JSPROP_ENUMERATE)) { return false; } return true; }
void DBRefInfo::construct(JSContext* cx, JS::CallArgs args) { if (!(args.length() == 2 || args.length() == 3)) uasserted(ErrorCodes::BadValue, "DBRef needs 2 or 3 arguments"); if (!args.get(0).isString()) uasserted(ErrorCodes::BadValue, "DBRef 1st parameter must be a string"); JS::RootedObject thisv(cx, JS_NewPlainObject(cx)); ObjectWrapper o(cx, thisv); o.setValue(InternedString::dollar_ref, args.get(0)); o.setValue(InternedString::dollar_id, args.get(1)); if (args.length() == 3) { if (!args.get(2).isString()) uasserted(ErrorCodes::BadValue, "DBRef 3rd parameter must be a string"); o.setValue(InternedString::dollar_db, args.get(2)); } JS::RootedObject out(cx); DBRefInfo::make(cx, &out, o.toBSON(), nullptr, false); args.rval().setObjectOrNull(out); }
BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { MozJSEntry entry(this); JS::RootedValue function(_context); ValueReader(_context, &function).fromBSONElement(args.firstElement(), args, true); int argc = args.nFields() - 1; JS::AutoValueVector argv(_context); BSONObjIterator it(args); it.next(); JS::RootedValue value(_context); for (int i = 0; i < argc; ++i) { ValueReader(_context, &value).fromBSONElement(*it, args, true); argv.append(value); it.next(); } JS::RootedValue out(_context); JS::RootedObject thisv(_context); _checkErrorState(JS::Call(_context, thisv, function, argv, &out), false, true); JS::RootedObject rout(_context, JS_NewPlainObject(_context)); ObjectWrapper wout(_context, rout); wout.setValue("ret", out); return wout.toBSON(); }
bool BroadcastSystemMessage(const nsAString& aType, const InfallibleTArray<BluetoothNamedValue>& aData) { mozilla::AutoSafeJSContext cx; MOZ_ASSERT(!::JS_IsExceptionPending(cx), "Shouldn't get here when an exception is pending!"); JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx)); if (!obj) { BT_WARNING("Failed to new JSObject for system message!"); return false; } if (!SetJsObject(cx, aData, obj)) { BT_WARNING("Failed to set properties of system message!"); return false; } nsCOMPtr<nsISystemMessagesInternal> systemMessenger = do_GetService("@mozilla.org/system-message-internal;1"); NS_ENSURE_TRUE(systemMessenger, false); JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*obj)); systemMessenger->BroadcastMessage(aType, value, JS::UndefinedHandleValue); return true; }
JSObject* CreateGCThing(JSContext* cx) { JS::RootedObject obj(cx, JS_NewPlainObject(cx)); if (!obj) return nullptr; JS_DefineProperty(cx, obj, "x", 42, 0); return obj; }
bool WebrtcTelemetry::GetWebrtcStats(JSContext *cx, JS::MutableHandle<JS::Value> ret) { JS::Rooted<JSObject*> root_obj(cx, JS_NewPlainObject(cx)); if (!root_obj) return false; ret.setObject(*root_obj); JS::Rooted<JSObject*> ice_obj(cx, JS_NewPlainObject(cx)); if (!ice_obj) return false; JS_DefineProperty(cx, root_obj, "IceCandidatesStats", ice_obj, JSPROP_ENUMERATE); if (!AddIceInfo(cx, ice_obj, false)) return false; if (!AddIceInfo(cx, ice_obj, true)) return false; return true; }
CStdDeserializer::CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream) : m_ScriptInterface(scriptInterface), m_Stream(stream), m_dummyObject(scriptInterface.GetJSRuntime()) { JSContext* cx = m_ScriptInterface.GetContext(); JSAutoRequest rq(cx); JS_AddExtraGCRootsTracer(m_ScriptInterface.GetJSRuntime(), CStdDeserializer::Trace, this); // Add a dummy tag because the serializer uses the tag 0 to indicate that a value // needs to be serialized and then tagged m_dummyObject = JS_NewPlainObject(cx); m_ScriptBackrefs.push_back(JS::Heap<JSObject*>(m_dummyObject)); }
bool WebrtcTelemetry::AddIceInfo(JSContext *cx, JS::Handle<JSObject*> iceObj, const bool loop) { JS::Rooted<JSObject*> statsObj(cx, JS_NewPlainObject(cx)); if (!statsObj) return false; AutoHashtable<WebrtcIceCandidateType>::ReflectEntryFunc reflectFunction = loop ? ReflectIceLoop : ReflectIceWebrtc; if (!mWebrtcIceCandidates.ReflectIntoJS(reflectFunction, cx, statsObj)) { return false; } return JS_DefineProperty(cx, iceObj, loop ? "loop" : "webrtc", statsObj, JSPROP_ENUMERATE); }
void JSWindowActor::ReceiveMessageOrQuery( JSContext* aCx, const JSWindowActorMessageMeta& aMetadata, JS::Handle<JS::Value> aData, ErrorResult& aRv) { // The argument which we want to pass to IPC. RootedDictionary<ReceiveMessageArgument> argument(aCx); argument.mObjects = JS_NewPlainObject(aCx); argument.mTarget = this; argument.mName = aMetadata.messageName(); argument.mData = aData; argument.mJson = aData; argument.mSync = false; JS::Rooted<JSObject*> self(aCx, GetWrapper()); JS::Rooted<JSObject*> global(aCx, JS::GetNonCCWObjectGlobal(self)); // We only need to create a promise if we're dealing with a query here. It // will be resolved or rejected once the listener has been called. Our // listener on this promise will then send the reply. RefPtr<Promise> promise; if (aMetadata.kind() == JSWindowActorMessageKind::Query) { promise = Promise::Create(xpc::NativeGlobal(global), aRv); if (NS_WARN_IF(aRv.Failed())) { return; } RefPtr<QueryHandler> handler = new QueryHandler(this, aMetadata); promise->AppendNativeHandler(handler); } // Invoke the actual callback. JS::Rooted<JS::Value> retval(aCx); RefPtr<MessageListener> messageListener = new MessageListener(self, global, nullptr, nullptr); messageListener->ReceiveMessage(argument, &retval, aRv, "JSWindowActor receive message"); // If we have a promise, resolve or reject it respectively. if (promise) { if (aRv.Failed()) { promise->MaybeReject(aRv); } else { promise->MaybeResolve(aCx, retval); } } }
static bool constructHook(JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); // Check that arguments were passed properly from JS_New. JS::RootedObject obj(cx, JS_NewPlainObject(cx)); if (!obj) { JS_ReportError(cx, "test failed, could not construct object"); return false; } if (strcmp(JS_GetClass(obj)->name, "Object") != 0) { JS_ReportError(cx, "test failed, wrong class for 'this'"); return false; } if (args.length() != 3) { JS_ReportError(cx, "test failed, argc == %d", args.length()); return false; } if (!args[0].isInt32() || args[2].toInt32() != 2) { JS_ReportError(cx, "test failed, wrong value in args[2]"); return false; } if (!args.isConstructing()) { JS_ReportError(cx, "test failed, not constructing"); return false; } // Perform a side-effect to indicate that this hook was actually called. JS::RootedValue value(cx, args[0]); JS::RootedObject callee(cx, &args.callee()); if (!JS_SetElement(cx, callee, 0, value)) return false; args.rval().setObject(*obj); // trash the argv, perversely args[0].setUndefined(); args[1].setUndefined(); args[2].setUndefined(); return true; }
bool BroadcastSystemMessage(const nsAString& aType, const BluetoothValue& aData) { mozilla::AutoSafeJSContext cx; MOZ_ASSERT(!::JS_IsExceptionPending(cx), "Shouldn't get here when an exception is pending!"); nsCOMPtr<nsISystemMessagesInternal> systemMessenger = do_GetService("@mozilla.org/system-message-internal;1"); NS_ENSURE_TRUE(systemMessenger, false); JS::Rooted<JS::Value> value(cx); if (aData.type() == BluetoothValue::TnsString) { JSString* jsData = JS_NewUCStringCopyN(cx, aData.get_nsString().BeginReading(), aData.get_nsString().Length()); value.setString(jsData); } else if (aData.type() == BluetoothValue::TArrayOfBluetoothNamedValue) { JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx)); if (!obj) { BT_WARNING("Failed to new JSObject for system message!"); return false; } if (!SetJsObject(cx, aData, obj)) { BT_WARNING("Failed to set properties of system message!"); return false; } value = JS::ObjectValue(*obj); } else { BT_WARNING("Not support the unknown BluetoothValue type"); return false; } nsCOMPtr<nsISupports> promise; systemMessenger->BroadcastMessage(aType, value, JS::UndefinedHandleValue, getter_AddRefs(promise)); return true; }
JSObject* newCCW(JS::HandleObject sourceZone, JS::HandleObject destZone) { /* * Now ensure that this zone will be swept first by adding a cross * compartment wrapper to a new objct in the same zone as the * delegate obejct. */ JS::RootedObject object(cx); { JSAutoCompartment ac(cx, destZone); object = JS_NewPlainObject(cx); if (!object) return nullptr; } { JSAutoCompartment ac(cx, sourceZone); if (!JS_WrapObject(cx, &object)) return nullptr; } return object; }
nsresult GetResult(JSContext* aCx, const FileRequestMetadata* aMetadata, JS::MutableHandle<JS::Value> aResult) { JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx)); if (NS_WARN_IF(!obj)) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } const FileRequestSize& size = aMetadata->size(); if (size.type() != FileRequestSize::Tvoid_t) { MOZ_ASSERT(size.type() == FileRequestSize::Tuint64_t); JS::Rooted<JS::Value> number(aCx, JS_NumberValue(size.get_uint64_t())); if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "size", number, 0))) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } } const FileRequestLastModified& lastModified = aMetadata->lastModified(); if (lastModified.type() != FileRequestLastModified::Tvoid_t) { MOZ_ASSERT(lastModified.type() == FileRequestLastModified::Tint64_t); JS::Rooted<JSObject*> date(aCx, JS::NewDateObject(aCx, JS::TimeClip(lastModified.get_int64_t()))); if (NS_WARN_IF(!date)) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "lastModified", date, 0))) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } } aResult.setObject(*obj); return NS_OK; }
FRAGMENT(JSObject, simple) { AutoSuppressHazardsForTest noanalysis; JS::Rooted<JSObject*> glob(cx, JS::CurrentGlobalOrNull(cx)); JS::Rooted<JSObject*> plain(cx, JS_NewPlainObject(cx)); JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx)); JS::Rooted<JSObject*> func(cx, (JSObject*) JS_NewFunction(cx, (JSNative) 1, 0, 0, "dys")); JS::Rooted<JSObject*> anon(cx, (JSObject*) JS_NewFunction(cx, (JSNative) 1, 0, 0, nullptr)); JS::Rooted<JSFunction*> funcPtr(cx, JS_NewFunction(cx, (JSNative) 1, 0, 0, "formFollows")); JSObject& plainRef = *plain; JSFunction& funcRef = *funcPtr; JSObject* plainRaw = plain; JSObject* funcRaw = func; // JS_NewObject will now assert if you feed it a bad class name, so mangle // the name after construction. char namebuf[20] = "goodname"; static JSClass cls { namebuf }; JS::RootedObject badClassName(cx, JS_NewObject(cx, &cls)); strcpy(namebuf, "\xc7X"); breakpoint(); use(glob); use(plain); use(func); use(anon); use(funcPtr); use(&plainRef); use(&funcRef); use(plainRaw); use(funcRaw); }
JSObject* newKey() { return JS_NewPlainObject(cx); }
jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject appendParent) { JSContext* cx = m_ScriptInterface.GetContext(); JSAutoRequest rq(cx); uint8_t type; NumberU8_Unbounded("type", type); switch (type) { case SCRIPT_TYPE_VOID: return JS::UndefinedValue(); case SCRIPT_TYPE_NULL: return JS::NullValue(); case SCRIPT_TYPE_ARRAY: case SCRIPT_TYPE_OBJECT: case SCRIPT_TYPE_OBJECT_PROTOTYPE: { JS::RootedObject obj(cx); if (appendParent) { obj.set(appendParent); } else if (type == SCRIPT_TYPE_ARRAY) { u32 length; NumberU32_Unbounded("array length", length); obj.set(JS_NewArrayObject(cx, length)); } else if (type == SCRIPT_TYPE_OBJECT) { obj.set(JS_NewPlainObject(cx)); } else // SCRIPT_TYPE_OBJECT_PROTOTYPE { std::wstring prototypeName; String("proto name", prototypeName, 0, 256); // Get constructor object JS::RootedObject proto(cx); GetSerializablePrototype(prototypeName, &proto); if (!proto) throw PSERROR_Deserialize_ScriptError("Failed to find serializable prototype for object"); JS::RootedObject parent(cx, JS_GetParent(proto)); if (!proto || !parent) throw PSERROR_Deserialize_ScriptError(); // TODO: Remove support for parent since this is dropped upstream SpiderMonkey obj.set(JS_NewObjectWithGivenProto(cx, nullptr, proto, parent)); if (!obj) throw PSERROR_Deserialize_ScriptError("JS_NewObject failed"); // Does it have custom Deserialize function? // if so, we let it handle the deserialized data, rather than adding properties directly bool hasCustomDeserialize, hasCustomSerialize; if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize) || !JS_HasProperty(cx, obj, "Deserialize", &hasCustomDeserialize)) throw PSERROR_Serialize_ScriptError("JS_HasProperty failed"); if (hasCustomDeserialize) { AddScriptBackref(obj); JS::RootedValue serialize(cx); if (!JS_GetProperty(cx, obj, "Serialize", &serialize)) throw PSERROR_Serialize_ScriptError("JS_GetProperty failed"); bool hasNullSerialize = hasCustomSerialize && serialize.isNull(); // If Serialize is null, we'll still call Deserialize but with undefined argument JS::RootedValue data(cx); if (!hasNullSerialize) ScriptVal("data", &data); JS::RootedValue objVal(cx, JS::ObjectValue(*obj)); m_ScriptInterface.CallFunctionVoid(objVal, "Deserialize", data); return JS::ObjectValue(*obj); } } if (!obj) throw PSERROR_Deserialize_ScriptError("Deserializer failed to create new object"); AddScriptBackref(obj); uint32_t numProps; NumberU32_Unbounded("num props", numProps); bool isLatin1; for (uint32_t i = 0; i < numProps; ++i) { Bool("isLatin1", isLatin1); if (isLatin1) { std::vector<JS::Latin1Char> propname; ReadStringLatin1("prop name", propname); JS::RootedValue propval(cx, ReadScriptVal("prop value", JS::NullPtr())); utf16string prp(propname.begin(), propname.end());; // TODO: Should ask upstream about getting a variant of JS_SetProperty with a length param. if (!JS_SetUCProperty(cx, obj, (const char16_t*)prp.data(), prp.length(), propval)) throw PSERROR_Deserialize_ScriptError(); } else { utf16string propname; ReadStringUTF16("prop name", propname); JS::RootedValue propval(cx, ReadScriptVal("prop value", JS::NullPtr())); if (!JS_SetUCProperty(cx, obj, (const char16_t*)propname.data(), propname.length(), propval)) throw PSERROR_Deserialize_ScriptError(); } } return JS::ObjectValue(*obj); } case SCRIPT_TYPE_STRING: { JS::RootedString str(cx); ScriptString("string", &str); return JS::StringValue(str); } case SCRIPT_TYPE_INT: { int32_t value; NumberI32("value", value, JSVAL_INT_MIN, JSVAL_INT_MAX); return JS::NumberValue(value); } case SCRIPT_TYPE_DOUBLE: { double value; NumberDouble_Unbounded("value", value); JS::RootedValue rval(cx, JS::NumberValue(value)); if (rval.isNull()) throw PSERROR_Deserialize_ScriptError("JS_NewNumberValue failed"); return rval; } case SCRIPT_TYPE_BOOLEAN: { uint8_t value; NumberU8("value", value, 0, 1); return JS::BooleanValue(value ? true : false); } case SCRIPT_TYPE_BACKREF: { u32 tag; NumberU32_Unbounded("tag", tag); JS::RootedObject obj(cx); GetScriptBackref(tag, &obj); if (!obj) throw PSERROR_Deserialize_ScriptError("Invalid backref tag"); return JS::ObjectValue(*obj); } case SCRIPT_TYPE_OBJECT_NUMBER: { double value; NumberDouble_Unbounded("value", value); JS::RootedValue val(cx, JS::NumberValue(value)); JS::RootedObject ctorobj(cx); if (!JS_GetClassObject(cx, JSProto_Number, &ctorobj)) throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); JS::RootedObject obj(cx, JS_New(cx, ctorobj, JS::HandleValueArray(val))); if (!obj) throw PSERROR_Deserialize_ScriptError("JS_New failed"); AddScriptBackref(obj); return JS::ObjectValue(*obj); } case SCRIPT_TYPE_OBJECT_STRING: { JS::RootedString str(cx); ScriptString("value", &str); if (!str) throw PSERROR_Deserialize_ScriptError(); JS::RootedValue val(cx, JS::StringValue(str)); JS::RootedObject ctorobj(cx); if (!JS_GetClassObject(cx, JSProto_String, &ctorobj)) throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); JS::RootedObject obj(cx, JS_New(cx, ctorobj, JS::HandleValueArray(val))); if (!obj) throw PSERROR_Deserialize_ScriptError("JS_New failed"); AddScriptBackref(obj); return JS::ObjectValue(*obj); } case SCRIPT_TYPE_OBJECT_BOOLEAN: { bool value; Bool("value", value); JS::RootedValue val(cx, JS::BooleanValue(value)); JS::RootedObject ctorobj(cx); if (!JS_GetClassObject(cx, JSProto_Boolean, &ctorobj)) throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); JS::RootedObject obj(cx, JS_New(cx, ctorobj, JS::HandleValueArray(val))); if (!obj) throw PSERROR_Deserialize_ScriptError("JS_New failed"); AddScriptBackref(obj); return JS::ObjectValue(*obj); } case SCRIPT_TYPE_TYPED_ARRAY: { u8 arrayType; u32 byteOffset, length; NumberU8_Unbounded("array type", arrayType); NumberU32_Unbounded("byte offset", byteOffset); NumberU32_Unbounded("length", length); // To match the serializer order, we reserve the typed array's backref tag here JS::RootedObject arrayObj(cx); AddScriptBackref(arrayObj); // Get buffer object JS::RootedValue bufferVal(cx, ReadScriptVal("buffer", JS::NullPtr())); if (!bufferVal.isObject()) throw PSERROR_Deserialize_ScriptError(); JS::RootedObject bufferObj(cx, &bufferVal.toObject()); if (!JS_IsArrayBufferObject(bufferObj)) throw PSERROR_Deserialize_ScriptError("js_IsArrayBuffer failed"); switch(arrayType) { case SCRIPT_TYPED_ARRAY_INT8: arrayObj = JS_NewInt8ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_UINT8: arrayObj = JS_NewUint8ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_INT16: arrayObj = JS_NewInt16ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_UINT16: arrayObj = JS_NewUint16ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_INT32: arrayObj = JS_NewInt32ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_UINT32: arrayObj = JS_NewUint32ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_FLOAT32: arrayObj = JS_NewFloat32ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_FLOAT64: arrayObj = JS_NewFloat64ArrayWithBuffer(cx, bufferObj, byteOffset, length); break; case SCRIPT_TYPED_ARRAY_UINT8_CLAMPED: arrayObj = JS_NewUint8ClampedArrayWithBuffer(cx, bufferObj, byteOffset, length); break; default: throw PSERROR_Deserialize_ScriptError("Failed to deserialize unrecognized typed array view"); } if (!arrayObj) throw PSERROR_Deserialize_ScriptError("js_CreateTypedArrayWithBuffer failed"); return JS::ObjectValue(*arrayObj); } case SCRIPT_TYPE_ARRAY_BUFFER: { u32 length; NumberU32_Unbounded("buffer length", length); #if BYTE_ORDER != LITTLE_ENDIAN #error TODO: need to convert JS ArrayBuffer data from little-endian #endif void* contents = malloc(length); ENSURE(contents); RawBytes("buffer data", (u8*)contents, length); JS::RootedObject bufferObj(cx, JS_NewArrayBufferWithContents(cx, length, contents)); AddScriptBackref(bufferObj); return JS::ObjectValue(*bufferObj); } case SCRIPT_TYPE_OBJECT_MAP: { JS::RootedObject obj(cx, JS::NewMapObject(cx)); AddScriptBackref(obj); u32 mapSize; NumberU32_Unbounded("map size", mapSize); for (u32 i=0; i<mapSize; ++i) { JS::RootedValue key(cx, ReadScriptVal("map key", JS::NullPtr())); JS::RootedValue value(cx, ReadScriptVal("map value", JS::NullPtr())); JS::MapSet(cx, obj, key, value); } return JS::ObjectValue(*obj); } case SCRIPT_TYPE_OBJECT_SET: { JS::RootedValue setVal(cx); m_ScriptInterface.Eval("(new Set())", &setVal); JS::RootedObject setObj(cx, &setVal.toObject()); AddScriptBackref(setObj); u32 setSize; NumberU32_Unbounded("set size", setSize); for (u32 i=0; i<setSize; ++i) { JS::RootedValue value(cx, ReadScriptVal("set value", JS::NullPtr())); m_ScriptInterface.CallFunctionVoid(setVal, "add", value); } return setVal; } default: throw PSERROR_Deserialize_OutOfBounds(); } }