Handle backrefs properly for maps and sets. Fixes #3374.
Allocate the tag for the backreference before deserializing the content, to match the order of serializing. This was SVN commit r16959.
This commit is contained in:
parent
acf7b7aefb
commit
2aef62d65f
@ -410,6 +410,9 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject
|
|||||||
NumberU32_Unbounded("map size", mapSize);
|
NumberU32_Unbounded("map size", mapSize);
|
||||||
JS::RootedValue mapVal(cx);
|
JS::RootedValue mapVal(cx);
|
||||||
m_ScriptInterface.Eval("(new Map())", &mapVal);
|
m_ScriptInterface.Eval("(new Map())", &mapVal);
|
||||||
|
|
||||||
|
// To match the serializer order, we reserve the map's backref tag here
|
||||||
|
u32 mapTag = ReserveScriptBackref();
|
||||||
|
|
||||||
for (u32 i=0; i<mapSize; ++i)
|
for (u32 i=0; i<mapSize; ++i)
|
||||||
{
|
{
|
||||||
@ -418,7 +421,7 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject
|
|||||||
m_ScriptInterface.CallFunctionVoid(mapVal, "set", key, value);
|
m_ScriptInterface.CallFunctionVoid(mapVal, "set", key, value);
|
||||||
}
|
}
|
||||||
JS::RootedObject mapObj(cx, &mapVal.toObject());
|
JS::RootedObject mapObj(cx, &mapVal.toObject());
|
||||||
AddScriptBackref(mapObj);
|
SetReservedScriptBackref(mapTag, mapObj);
|
||||||
return mapVal;
|
return mapVal;
|
||||||
}
|
}
|
||||||
case SCRIPT_TYPE_OBJECT_SET:
|
case SCRIPT_TYPE_OBJECT_SET:
|
||||||
@ -428,13 +431,16 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject
|
|||||||
JS::RootedValue setVal(cx);
|
JS::RootedValue setVal(cx);
|
||||||
m_ScriptInterface.Eval("(new Set())", &setVal);
|
m_ScriptInterface.Eval("(new Set())", &setVal);
|
||||||
|
|
||||||
|
// To match the serializer order, we reserve the set's backref tag here
|
||||||
|
u32 setTag = ReserveScriptBackref();
|
||||||
|
|
||||||
for (u32 i=0; i<setSize; ++i)
|
for (u32 i=0; i<setSize; ++i)
|
||||||
{
|
{
|
||||||
JS::RootedValue value(cx, ReadScriptVal("set value", JS::NullPtr()));
|
JS::RootedValue value(cx, ReadScriptVal("set value", JS::NullPtr()));
|
||||||
m_ScriptInterface.CallFunctionVoid(setVal, "add", value);
|
m_ScriptInterface.CallFunctionVoid(setVal, "add", value);
|
||||||
}
|
}
|
||||||
JS::RootedObject setObj(cx, &setVal.toObject());
|
JS::RootedObject setObj(cx, &setVal.toObject());
|
||||||
AddScriptBackref(setObj);
|
SetReservedScriptBackref(setTag, setObj);
|
||||||
return setVal;
|
return setVal;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -633,6 +633,48 @@ public:
|
|||||||
"\x05" // SCRIPT_TYPE_INT
|
"\x05" // SCRIPT_TYPE_INT
|
||||||
"\x01\0\0\0" // 1
|
"\x01\0\0\0" // 1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
helper_script_roundtrip("Nested maps using backrefs",
|
||||||
|
"var a = new Map(); var b = new Map(); b.set(1, a); b.set(2, a); b",
|
||||||
|
/* expected: */
|
||||||
|
"({})",
|
||||||
|
/* expected stream: */
|
||||||
|
25,
|
||||||
|
"\x0f" // SCRIPT_TYPE_MAP
|
||||||
|
"\x02\0\0\0" // size
|
||||||
|
|
||||||
|
"\x05" // SCRIPT_TYPE_INT
|
||||||
|
"\x01\0\0\0" // 1
|
||||||
|
"\x0f" // SCRIPT_TYPE_MAP
|
||||||
|
"\0\0\0\0" // size
|
||||||
|
|
||||||
|
"\x05" // SCRIPT_TYPE_INT
|
||||||
|
"\x02\0\0\0" // 2
|
||||||
|
"\x08" // SCRIPT_TYPE_BACKREF
|
||||||
|
"\x02\0\0\0" // ref. to object #2, i.e. "a", with #1 being "b"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_script_set_nested()
|
||||||
|
{
|
||||||
|
helper_script_roundtrip("Nested sets using backrefs",
|
||||||
|
"var a = new Set(); var b = new Set(); a.add(b); a.add({\"bar\": b}); a",
|
||||||
|
/* expected: */
|
||||||
|
"({})",
|
||||||
|
/* expected stream: */
|
||||||
|
30,
|
||||||
|
"\x10" // SCRIPT_TYPE_SET
|
||||||
|
"\x02\0\0\0" // size
|
||||||
|
|
||||||
|
"\x10" // SCRIPT_TYPE_SET
|
||||||
|
"\x00\0\0\0" // size
|
||||||
|
|
||||||
|
"\x03" // SCRIPT_TYPE_OBJECT
|
||||||
|
"\x01\0\0\0" // num props
|
||||||
|
"\x03\0\0\0" "b\0a\0r\0" // "bar"
|
||||||
|
"\x08" // SCRIPT_TYPE_BACKREF
|
||||||
|
"\x02\0\0\0" // ref to object #2, i.e. "b", with #1 being "a"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: prototype objects
|
// TODO: prototype objects
|
||||||
|
Loading…
Reference in New Issue
Block a user