Bug 560650 - TM: json code should use JS_Enumerate. r=gal

This commit is contained in:
Robert Sayre 2010-04-24 14:18:10 -04:00
parent 9e4725da95
commit 7bf54364f0
3 changed files with 33 additions and 140 deletions

View File

@ -97,18 +97,6 @@ function getTestPairs() {
return testPairs;
}
function testIterator() {
// custom iterator: JS 1.7+
var x = {
"a": "foo",
b: "not included",
c: "bar",
"4": "qux",
__iterator__: function() { return (function() { yield "a"; yield "c"; yield 4; })() }
}
do_check_eq('{"a":"foo","c":"bar","4":"qux"}', nativeJSON.encode(x));
}
function testStringEncode() {
// test empty arg
do_check_eq(null, nativeJSON.encode());
@ -185,61 +173,9 @@ function throwingToJSON() {
} catch (ex) {}
}
function throwingIterator() {
var a = {
"b": 1,
"c": 2,
__iterator__: function() { yield "b"; throw("uh oh"); }
}
try {
var y = nativeJSON.encode(a);
} catch (ex) {}
}
function deletingIter(x) {
return function() {
yield "dd";
print("after first yield");
delete x["a"]["c"];
gc();
print("about to yield second");
yield "ddddd";
}
}
function deleteDuringEncode() {
var x = {};
x.a = {
b: 1,
bb: 2,
bbb: 3,
c: {
cc: 2,
ccc: 3,
d: {
dd: 2,
ddd: 3,
__iterator__: deletingIter(x),
dddd: 4,
ddddd: 5
},
cccc: 4,
ccccc: 5
},
bbbb: 4,
bbbbb: 5,
bbbbbb: 6
};
var z = nativeJSON.encode(x);
print(z);
}
function run_test() {
testStringEncode();
testIterator();
throwingToJSON();
throwingIterator();
deleteDuringEncode();
// failing on windows -- bug 410005
// testOutputStreams();

View File

@ -87,16 +87,6 @@ function getTestPairs() {
var y = new X();
testPairs.push(['{"a":"b"}', y]);
// custom iterator: JS 1.7+
var x = {
"a": "foo",
b: "not included",
c: "bar",
"4": "qux",
__iterator__: function() { return (function() { yield "a"; yield "c"; yield 4; })() }
}
do_check_eq('{"a":"foo","c":"bar","4":"qux"}', JSON.stringify(x));
return testPairs;
}

View File

@ -257,83 +257,61 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx)
if (!scx->cb.append('{'))
return JS_FALSE;
jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
jsval vec[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
jsval& key = vec[0];
jsval& outputValue = vec[1];
jsval& outputValue = vec[0];
jsval& whitelistElement = vec[1];
jsid& id = vec[2];
JSObject *iterObj = NULL;
jsval *keySource = vp;
bool usingWhitelist = false;
// if the replacer is an array, we use the keys from it
if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) {
usingWhitelist = true;
vec[2] = OBJECT_TO_JSVAL(scx->replacer);
keySource = &vec[2];
vec[3] = OBJECT_TO_JSVAL(scx->replacer);
keySource = &vec[3];
}
if (!js_ValueToIterator(cx, JSITER_ENUMERATE, keySource))
return JS_FALSE;
iterObj = JSVAL_TO_OBJECT(*keySource);
JSBool memberWritten = JS_FALSE;
AutoIdArray ida(cx, JS_Enumerate(cx, JSVAL_TO_OBJECT(*keySource)));
if (!ida)
return JS_FALSE;
bool ok = false;
while (true) {
for (jsint i = 0, len = ida.length(); i < len; i++) {
outputValue = JSVAL_VOID;
if (!js_CallIteratorNext(cx, iterObj, &key))
goto error_break;
if (key == JSVAL_HOLE)
break;
jsuint index = 0;
if (usingWhitelist) {
if (!usingWhitelist) {
if (!js_ValueToStringId(cx, ida[i], &id))
return JS_FALSE;
} else {
// skip non-index properties
if (!js_IdIsIndex(key, &index))
jsuint index = 0;
if (!js_IdIsIndex(ID_TO_VALUE(ida[i]), &index))
continue;
jsval newKey;
if (!scx->replacer->getProperty(cx, key, &newKey))
goto error_break;
key = newKey;
if (!scx->replacer->getProperty(cx, ID_TO_VALUE(ida[i]), &whitelistElement))
return JS_FALSE;
if (!js_ValueToStringId(cx, whitelistElement, &id))
return JS_FALSE;
}
JSString *ks;
if (JSVAL_IS_STRING(key)) {
ks = JSVAL_TO_STRING(key);
} else {
ks = js_ValueToString(cx, key);
if (!ks)
goto error_break;
}
AutoValueRooter keyStringRoot(cx, ks);
// Don't include prototype properties, since this operation is
// supposed to be implemented as if by ES3.1 Object.keys()
jsid id;
JSObject *obj2;
JSProperty *prop;
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(ks), &id) ||
!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &obj2, &prop)) {
goto error_break;
}
if (!prop)
continue;
obj2->dropProperty(cx, prop);
// We should have a string id by this point. Either from
// JS_Enumerate's id array, or by converting the values
// in the whitelist.
JS_ASSERT(JSVAL_IS_STRING(ID_TO_VALUE(id)));
if (!JS_GetPropertyById(cx, obj, id, &outputValue))
goto error_break;
return JS_FALSE;
if (JSVAL_IS_OBJECT(outputValue) && !js_TryJSON(cx, &outputValue))
goto error_break;
return JS_FALSE;
// call this here, so we don't write out keys if the replacer function
// wants to elide the value.
if (!CallReplacerFunction(cx, id, obj, scx, &outputValue))
goto error_break;
return JS_FALSE;
JSType type = JS_TypeOfValue(cx, outputValue);
@ -343,16 +321,16 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx)
// output a comma unless this is the first member to write
if (memberWritten && !scx->cb.append(','))
goto error_break;
return JS_FALSE;
memberWritten = JS_TRUE;
if (!WriteIndent(cx, scx, scx->depth))
goto error_break;
return JS_FALSE;
// Be careful below, this string is weakly rooted
JSString *s = js_ValueToString(cx, key);
JSString *s = js_ValueToString(cx, ID_TO_VALUE(id));
if (!s)
goto error_break;
return JS_FALSE;
const jschar *chars;
size_t length;
@ -360,20 +338,9 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx)
if (!write_string(cx, scx->cb, chars, length) ||
!scx->cb.append(':') ||
!Str(cx, id, obj, scx, &outputValue, false)) {
goto error_break;
return JS_FALSE;
}
}
ok = true;
error_break:
if (iterObj) {
// Always close the iterator, but make sure not to stomp on OK
JS_ASSERT(OBJECT_TO_JSVAL(iterObj) == *keySource);
ok &= !!js_CloseIterator(cx, *keySource);
}
if (!ok)
return JS_FALSE;
if (memberWritten && !WriteIndent(cx, scx, scx->depth - 1))
return JS_FALSE;