Stop boxing everything in the JSON parser

The JSON parser was producing structures that held all arrays in
RefData. This was to defeat copy-on-write, since ArrayDatas were
referenced from multiple places (i.e. the parser's internal stack of
in-flight objects, and the actual structure being built) and mutated. I
rectified this by not adding arrays into the overall structure until
they're done being modified. This necessitated introducing a separate
stack for keys, to handle this structure:

  { "key": { ... } }

When we see the opening { of the inner object, we push "key" onto the
stack, so that when we see the closing } of the inner object, we can
store it into the outer object under the right key.
Esse commit está contido em:
Owen Yamauchi
2013-05-07 16:04:52 -07:00
commit de Sara Golemon
commit a6663759d2
+20 -35
Ver Arquivo
@@ -293,6 +293,7 @@ static const int loose_state_transition_table[31][31] = {
struct json_parser {
int the_stack[JSON_PARSER_MAX_DEPTH];
Variant the_zstack[JSON_PARSER_MAX_DEPTH];
String the_kstack[JSON_PARSER_MAX_DEPTH];
int the_top;
int the_mark; // the watermark
};
@@ -301,10 +302,11 @@ IMPLEMENT_THREAD_LOCAL(json_parser, s_json_parser);
class JsonParserCleaner {
public:
JsonParserCleaner(json_parser *json) : m_json(json) {}
explicit JsonParserCleaner(json_parser *json) : m_json(json) {}
~JsonParserCleaner() {
for (int i = 0; i <= m_json->the_mark; i++) {
m_json->the_zstack[i].unset();
m_json->the_kstack[i].reset();
}
}
private:
@@ -430,46 +432,30 @@ static void utf16_to_utf8(StringBuffer &buf, unsigned short utf16) {
}
}
static void object_set(Variant &var, StringBuffer &key, CVarRef value,
static void object_set(Variant &var, CStrRef key, CVarRef value,
int assoc) {
String data = key.detach();
if (!assoc) {
// We know it is stdClass, and everything is public (and dynamic).
if (data.empty()) {
if (key.empty()) {
var.getObjectData()->o_set("_empty_", value);
} else {
var.getObjectData()->o_set(data, value);
var.getObjectData()->o_set(key, value);
}
} else {
var.set(data, value);
var.set(key, value);
}
}
static void object_set(Variant &var, StringBuffer &key, RefResult value,
int assoc) {
String data = key.detach();
if (!assoc) {
// We know it is stdClass, and everything is public (and dynamic).
if (data.empty()) {
var.getObjectData()->o_set("_empty_", value);
} else {
var.getObjectData()->o_set(data, value);
}
} else {
var.set(data, value);
}
}
static void attach_zval(json_parser *json, int up, int cur, StringBuffer &key,
static void attach_zval(json_parser *json, CStrRef key,
int assoc) {
Variant &root = json->the_zstack[up];
Variant &child = json->the_zstack[cur];
int up_mode = json->the_stack[up];
Variant &root = json->the_zstack[json->the_top - 1];
Variant &child = json->the_zstack[json->the_top];
int up_mode = json->the_stack[json->the_top - 1];
if (up_mode == MODE_ARRAY) {
root.append(ref(child));
root.append(child);
} else if (up_mode == MODE_OBJECT) {
object_set(root, key, ref(child), assoc);
object_set(root, key, child, assoc);
}
}
@@ -591,9 +577,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
} else {
top = Array::Create();
}
if (JSON(the_top) > 1) {
attach_zval(the_json, JSON(the_top-1), JSON(the_top), *key, assoc);
}
JSON(the_kstack)[JSON(the_top)] = key->detach();
JSON_RESET_TYPE();
}
break;
@@ -620,11 +604,12 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
Variant mval;
json_create_zval(mval, *buf, type);
Variant &top = JSON(the_zstack)[JSON(the_top)];
object_set(top, *key, mval, assoc);
object_set(top, key->detach(), mval, assoc);
buf->reset();
JSON_RESET_TYPE();
}
attach_zval(the_json, JSON(the_kstack)[JSON(the_top)], assoc);
if (!pop(the_json, MODE_OBJECT)) {
return false;
@@ -647,9 +632,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
JSON(the_zstack)[JSON(the_top)].unset();
}
JSON(the_zstack)[JSON(the_top)] = Array::Create();
if (JSON(the_top) > 1) {
attach_zval(the_json, JSON(the_top-1), JSON(the_top), *key, assoc);
}
JSON(the_kstack)[JSON(the_top)] = key->detach();
JSON_RESET_TYPE();
}
break;
@@ -667,6 +650,8 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
JSON_RESET_TYPE();
}
attach_zval(the_json, JSON(the_kstack[JSON(the_top)]), assoc);
if (!pop(the_json, MODE_ARRAY)) {
return false;
}
@@ -716,7 +701,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool assoc/*<fb>*/,
push(the_json, MODE_KEY)) {
if (type != -1) {
Variant &top = JSON(the_zstack)[JSON(the_top)];
object_set(top, *key, mval, assoc);
object_set(top, key->detach(), mval, assoc);
}
the_state = 29;
}