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;
}
Exemple #2
0
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;
}
Exemple #3
0
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);
}
Exemple #4
0
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();
}
Exemple #5
0
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;
}
Exemple #6
0
JSObject* CreateGCThing(JSContext* cx)
{
    JS::RootedObject obj(cx, JS_NewPlainObject(cx));
    if (!obj)
        return nullptr;
    JS_DefineProperty(cx, obj, "x", 42, 0);
    return obj;
}
Exemple #7
0
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;
}
Exemple #8
0
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));
}
Exemple #9
0
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);
}
Exemple #10
0
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;
}
Exemple #13
0
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;
  }
Exemple #15
0
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);
}
Exemple #16
0
JSObject* newKey()
{
    return JS_NewPlainObject(cx);
}
Exemple #17
0
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();
	}
}