--- trunk/instrument-js.c 2008/10/27 21:42:58 374 +++ trunk/instrument-js.cpp 2009/03/08 06:45:51 434 @@ -1,6 +1,6 @@ /* - instrument-js.c - JavaScript instrumentation routines - Copyright (C) 2007, 2008 siliconforks.com + instrument-js.cpp - JavaScript instrumentation routines + Copyright (C) 2007, 2008, 2009 siliconforks.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include "instrument-js.h" #include +#include #include #include @@ -52,7 +53,7 @@ struct IfDirective * next; }; -bool jscoverage_mozilla = false; +enum JSCoverageMode jscoverage_mode = JSCOVERAGE_NORMAL; static bool * exclusive_directives = NULL; @@ -267,7 +268,7 @@ } } -static void instrument_expression(JSParseNode * node, Stream * f); +static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals); static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); @@ -284,7 +285,7 @@ Stream_write_string(f, "each "); } Stream_write_char(f, '('); - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, false); Stream_write_char(f, ')'); } @@ -304,23 +305,43 @@ assert(if_node->pn_arity == PN_TERNARY); p = if_node->pn_kid2; } - assert(p->pn_arity == PN_UNARY); - p = p->pn_kid; - if (p->pn_type == TOK_YIELD) { - /* for generator expressions */ + switch (p->pn_arity) { + case PN_UNARY: p = p->pn_kid; + if (p->pn_type == TOK_YIELD) { + /* for generator expressions */ + p = p->pn_kid; + } + output_expression(p, f, false); + break; + case PN_LIST: + /* + When the array comprehension contains "if (0)", it will be optimized away and + the result will be an empty TOK_LC list. + */ + assert(p->pn_type == TOK_LC); + assert(p->pn_head == NULL); + /* the "1" is arbitrary (since the list is empty) */ + Stream_write_char(f, '1'); + break; + default: + abort(); + break; } - instrument_expression(p, f); p = for_node; while (p->pn_type == TOK_FOR) { Stream_write_char(f, ' '); output_for_in(p, f); p = p->pn_right; } - if (if_node) { + if (p->pn_type == TOK_LC) { + /* this is the optimized-away "if (0)" */ + Stream_write_string(f, " if (0)"); + } + else if (if_node) { Stream_write_string(f, " if ("); - instrument_expression(if_node->pn_kid1, f); + output_expression(if_node->pn_kid1, f, false); Stream_write_char(f, ')'); } } @@ -366,7 +387,7 @@ if (param == NULL) { destructuring = true; JSParseNode * expression = NULL; - assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY); + assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_SEQ); JSParseNode * semi = node->pn_body->pn_head; assert(semi->pn_type == TOK_SEMI); JSParseNode * comma = semi->pn_kid; @@ -381,7 +402,7 @@ } } assert(expression != NULL); - instrument_expression(expression, f); + output_expression(expression, f, false); } else { print_string_atom(param, f); @@ -393,7 +414,7 @@ /* function body */ if (function->flags & JSFUN_EXPR_CLOSURE) { /* expression closure - use output_statement instead of instrument_statement */ - if (node->pn_body->pn_type == TOK_BODY) { + if (node->pn_body->pn_type == TOK_SEQ) { assert(node->pn_body->pn_arity == PN_LIST); assert(node->pn_body->pn_count == 2); output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false); @@ -414,7 +435,7 @@ } } - Stream_write_string(f, "}\n"); + Stream_write_char(f, '}'); } static void instrument_function_call(JSParseNode * node, Stream * f) { @@ -433,21 +454,14 @@ Stream_write_char(f, ')'); return; } - else { - Stream_write_char(f, '('); - instrument_expression(function_node, f); - Stream_write_char(f, ')'); - } - } - else { - instrument_expression(function_node, f); } + output_expression(function_node, f, false); Stream_write_char(f, '('); for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) { if (p != node->pn_head->pn_next) { Stream_write_string(f, ", "); } - instrument_expression(p, f); + output_expression(p, f, false); } Stream_write_char(f, ')'); } @@ -455,33 +469,10 @@ static void instrument_declarations(JSParseNode * list, Stream * f) { assert(list->pn_arity == PN_LIST); for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) { - switch (p->pn_type) { - case TOK_NAME: - assert(p->pn_arity == PN_NAME); - if (p != list->pn_head) { - Stream_write_string(f, ", "); - } - print_string_atom(p->pn_atom, f); - if (p->pn_expr != NULL) { - Stream_write_string(f, " = "); - instrument_expression(p->pn_expr, f); - } - break; - case TOK_ASSIGN: - /* destructuring */ - instrument_expression(p->pn_left, f); - Stream_write_string(f, " = "); - instrument_expression(p->pn_right, f); - break; - case TOK_RB: - case TOK_RC: - /* destructuring */ - instrument_expression(p, f); - break; - default: - abort(); - break; + if (p != list->pn_head) { + Stream_write_string(f, ", "); } + output_expression(p, f, false); } } @@ -498,29 +489,23 @@ TOK_INSTANCEOF binary TOK_IN binary */ -static void instrument_expression(JSParseNode * node, Stream * f) { +static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals) { switch (node->pn_type) { case TOK_FUNCTION: + Stream_write_char(f, '('); instrument_function(node, f, 0, FUNCTION_NORMAL); + Stream_write_char(f, ')'); break; case TOK_COMMA: for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { if (p != node->pn_head) { Stream_write_string(f, ", "); } - instrument_expression(p, f); + output_expression(p, f, parenthesize_object_literals); } break; case TOK_ASSIGN: - if (node->pn_left->pn_type == TOK_RC) { - /* destructuring assignment with object literal must be in parentheses */ - Stream_write_char(f, '('); - instrument_expression(node->pn_left, f); - Stream_write_char(f, ')'); - } - else { - instrument_expression(node->pn_left, f); - } + output_expression(node->pn_left, f, parenthesize_object_literals); Stream_write_char(f, ' '); switch (node->pn_op) { case JSOP_ADD: @@ -541,14 +526,14 @@ break; } Stream_write_string(f, "= "); - instrument_expression(node->pn_right, f); + output_expression(node->pn_right, f, false); break; case TOK_HOOK: - instrument_expression(node->pn_kid1, f); + output_expression(node->pn_kid1, f, parenthesize_object_literals); Stream_write_string(f, "? "); - instrument_expression(node->pn_kid2, f); + output_expression(node->pn_kid2, f, false); Stream_write_string(f, ": "); - instrument_expression(node->pn_kid3, f); + output_expression(node->pn_kid3, f, false); break; case TOK_OR: case TOK_AND: @@ -564,16 +549,19 @@ case TOK_DIVOP: switch (node->pn_arity) { case PN_BINARY: - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, parenthesize_object_literals); Stream_printf(f, " %s ", get_op(node->pn_op)); - instrument_expression(node->pn_right, f); + output_expression(node->pn_right, f, false); break; case PN_LIST: for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { - if (p != node->pn_head) { + if (p == node->pn_head) { + output_expression(p, f, parenthesize_object_literals); + } + else { Stream_printf(f, " %s ", get_op(node->pn_op)); + output_expression(p, f, false); } - instrument_expression(p, f); } break; default: @@ -583,28 +571,28 @@ case TOK_UNARYOP: switch (node->pn_op) { case JSOP_NEG: - Stream_write_char(f, '-'); - instrument_expression(node->pn_kid, f); + Stream_write_string(f, "- "); + output_expression(node->pn_kid, f, false); break; case JSOP_POS: - Stream_write_char(f, '+'); - instrument_expression(node->pn_kid, f); + Stream_write_string(f, "+ "); + output_expression(node->pn_kid, f, false); break; case JSOP_NOT: - Stream_write_char(f, '!'); - instrument_expression(node->pn_kid, f); + Stream_write_string(f, "! "); + output_expression(node->pn_kid, f, false); break; case JSOP_BITNOT: - Stream_write_char(f, '~'); - instrument_expression(node->pn_kid, f); + Stream_write_string(f, "~ "); + output_expression(node->pn_kid, f, false); break; case JSOP_TYPEOF: Stream_write_string(f, "typeof "); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, false); break; case JSOP_VOID: Stream_write_string(f, "void "); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, false); break; default: fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op); @@ -621,24 +609,24 @@ case JSOP_INCPROP: case JSOP_INCELEM: Stream_write_string(f, "++"); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, false); break; case JSOP_DECNAME: case JSOP_DECPROP: case JSOP_DECELEM: Stream_write_string(f, "--"); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, false); break; case JSOP_NAMEINC: case JSOP_PROPINC: case JSOP_ELEMINC: - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, parenthesize_object_literals); Stream_write_string(f, "++"); break; case JSOP_NAMEDEC: case JSOP_PROPDEC: case JSOP_ELEMDEC: - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, parenthesize_object_literals); Stream_write_string(f, "--"); break; default: @@ -652,15 +640,25 @@ break; case TOK_DELETE: Stream_write_string(f, "delete "); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, false); break; case TOK_DOT: + /* numeric literals must be parenthesized */ + switch (node->pn_expr->pn_type) { + case TOK_NUMBER: + Stream_write_char(f, '('); + output_expression(node->pn_expr, f, false); + Stream_write_char(f, ')'); + break; + default: + output_expression(node->pn_expr, f, true); + break; + } /* This may have originally been x['foo-bar']. Because the string 'foo-bar' contains illegal characters, we have to use the subscript syntax instead of the dot syntax. */ - instrument_expression(node->pn_expr, f); assert(ATOM_IS_STRING(node->pn_atom)); { JSString * s = ATOM_TO_STRING(node->pn_atom); @@ -689,9 +687,9 @@ } break; case TOK_LB: - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, false); Stream_write_char(f, '['); - instrument_expression(node->pn_right, f); + output_expression(node->pn_right, f, false); Stream_write_char(f, ']'); break; case TOK_LP: @@ -705,7 +703,7 @@ } /* TOK_COMMA is a special case: a hole in the array */ if (p->pn_type != TOK_COMMA) { - instrument_expression(p, f); + output_expression(p, f, false); } } if (node->pn_extra == PNX_ENDCOMMA) { @@ -714,6 +712,9 @@ Stream_write_char(f, ']'); break; case TOK_RC: + if (parenthesize_object_literals) { + Stream_write_char(f, '('); + } Stream_write_char(f, '{'); for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { if (p->pn_type != TOK_COLON) { @@ -733,28 +734,36 @@ else { Stream_write_string(f, "set "); } - instrument_expression(p->pn_left, f); + output_expression(p->pn_left, f, false); + Stream_write_char(f, ' '); if (p->pn_right->pn_type != TOK_FUNCTION) { fatal_source(file_id, p->pn_pos.begin.lineno, "expected function"); } instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); break; default: - instrument_expression(p->pn_left, f); + output_expression(p->pn_left, f, false); Stream_write_string(f, ": "); - instrument_expression(p->pn_right, f); + output_expression(p->pn_right, f, false); break; } } Stream_write_char(f, '}'); + if (parenthesize_object_literals) { + Stream_write_char(f, ')'); + } break; case TOK_RP: Stream_write_char(f, '('); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, false); Stream_write_char(f, ')'); break; case TOK_NAME: print_string_atom(node->pn_atom, f); + if (node->pn_expr != NULL) { + Stream_write_string(f, " = "); + output_expression(node->pn_expr, f, false); + } break; case TOK_STRING: print_quoted_string_atom(node->pn_atom, f); @@ -776,7 +785,21 @@ To keep the output simple, special-case zero. */ if (node->pn_dval == 0.0) { - Stream_write_string(f, "0"); + if (signbit(node->pn_dval)) { + Stream_write_string(f, "-0"); + } + else { + Stream_write_string(f, "0"); + } + } + else if (node->pn_dval == INFINITY) { + Stream_write_string(f, "Number.POSITIVE_INFINITY"); + } + else if (node->pn_dval == -INFINITY) { + Stream_write_string(f, "Number.NEGATIVE_INFINITY"); + } + else if (isnan(node->pn_dval)) { + Stream_write_string(f, "Number.NaN"); } else { Stream_printf(f, "%.15g", node->pn_dval); @@ -802,14 +825,14 @@ } break; case TOK_INSTANCEOF: - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, parenthesize_object_literals); Stream_write_string(f, " instanceof "); - instrument_expression(node->pn_right, f); + output_expression(node->pn_right, f, false); break; case TOK_IN: - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, false); Stream_write_string(f, " in "); - instrument_expression(node->pn_right, f); + output_expression(node->pn_right, f, false); break; case TOK_LEXICALSCOPE: assert(node->pn_arity == PN_NAME); @@ -820,14 +843,14 @@ assert(node->pn_expr->pn_left->pn_arity == PN_LIST); instrument_declarations(node->pn_expr->pn_left, f); Stream_write_string(f, ") "); - instrument_expression(node->pn_expr->pn_right, f); + output_expression(node->pn_expr->pn_right, f, true); break; case TOK_YIELD: assert(node->pn_arity == PN_UNARY); Stream_write_string(f, "yield"); if (node->pn_kid != NULL) { Stream_write_char(f, ' '); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, true); } break; case TOK_ARRAYCOMP: @@ -869,6 +892,7 @@ switch (node->pn_type) { case TOK_FUNCTION: instrument_function(node, f, indent, FUNCTION_NORMAL); + Stream_write_char(f, '\n'); break; case TOK_LC: assert(node->pn_arity == PN_LIST); @@ -899,7 +923,7 @@ Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "if ("); - instrument_expression(node->pn_kid1, f); + output_expression(node->pn_kid1, f, false); Stream_write_string(f, ") {\n"); if (is_jscoverage_if && node->pn_kid3) { uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno; @@ -936,7 +960,7 @@ assert(node->pn_arity == PN_BINARY); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "switch ("); - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, false); Stream_write_string(f, ") {\n"); { JSParseNode * list = node->pn_right; @@ -948,7 +972,7 @@ switch (p->pn_type) { case TOK_CASE: Stream_write_string(f, "case "); - instrument_expression(p->pn_left, f); + output_expression(p->pn_left, f, false); Stream_write_string(f, ":\n"); break; case TOK_DEFAULT: @@ -972,7 +996,7 @@ assert(node->pn_arity == PN_BINARY); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "while ("); - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, false); Stream_write_string(f, ") {\n"); instrument_statement(node->pn_right, f, indent + 2, false); Stream_write_string(f, "}\n"); @@ -985,7 +1009,7 @@ Stream_write_string(f, "}\n"); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "while ("); - instrument_expression(node->pn_right, f); + output_expression(node->pn_right, f, false); Stream_write_string(f, ");\n"); break; case TOK_FOR: @@ -997,22 +1021,22 @@ assert(node->pn_left->pn_arity == PN_BINARY); output_for_in(node, f); break; - case TOK_RESERVED: + case TOK_FORHEAD: /* for (;;) */ assert(node->pn_left->pn_arity == PN_TERNARY); Stream_write_string(f, "for ("); if (node->pn_left->pn_kid1) { - instrument_expression(node->pn_left->pn_kid1, f); + output_expression(node->pn_left->pn_kid1, f, false); } Stream_write_string(f, ";"); if (node->pn_left->pn_kid2) { Stream_write_char(f, ' '); - instrument_expression(node->pn_left->pn_kid2, f); + output_expression(node->pn_left->pn_kid2, f, false); } Stream_write_string(f, ";"); if (node->pn_left->pn_kid3) { Stream_write_char(f, ' '); - instrument_expression(node->pn_left->pn_kid3, f); + output_expression(node->pn_left->pn_kid3, f, false); } Stream_write_char(f, ')'); break; @@ -1028,7 +1052,7 @@ assert(node->pn_arity == PN_UNARY); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "throw "); - instrument_expression(node->pn_u.unary.kid, f); + output_expression(node->pn_u.unary.kid, f, false); Stream_write_string(f, ";\n"); break; case TOK_TRY: @@ -1041,22 +1065,17 @@ assert(node->pn_kid2->pn_type == TOK_RESERVED); for (JSParseNode * scope = node->pn_kid2->pn_head; scope != NULL; scope = scope->pn_next) { assert(scope->pn_type == TOK_LEXICALSCOPE); - JSParseNode * catch = scope->pn_expr; - assert(catch->pn_type == TOK_CATCH); + JSParseNode * catch_node = scope->pn_expr; + assert(catch_node->pn_type == TOK_CATCH); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "catch ("); - /* this may not be a name - destructuring assignment */ - /* - assert(catch->pn_kid1->pn_arity == PN_NAME); - print_string_atom(catch->pn_kid1->pn_atom, f); - */ - instrument_expression(catch->pn_kid1, f); - if (catch->pn_kid2) { + output_expression(catch_node->pn_kid1, f, false); + if (catch_node->pn_kid2) { Stream_write_string(f, " if "); - instrument_expression(catch->pn_kid2, f); + output_expression(catch_node->pn_kid2, f, false); } Stream_write_string(f, ") {\n"); - instrument_statement(catch->pn_kid3, f, indent + 2, false); + instrument_statement(catch_node->pn_kid3, f, indent + 2, false); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "}\n"); } @@ -1077,8 +1096,7 @@ assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue"); - JSAtom * atom = node->pn_u.name.atom; - if (atom != NULL) { + if (node->pn_atom != NULL) { Stream_write_char(f, ' '); print_string_atom(node->pn_atom, f); } @@ -1088,7 +1106,7 @@ assert(node->pn_arity == PN_BINARY); Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "with ("); - instrument_expression(node->pn_left, f); + output_expression(node->pn_left, f, false); Stream_write_string(f, ") {\n"); instrument_statement(node->pn_right, f, indent + 2, false); Stream_printf(f, "%*s", indent, ""); @@ -1096,7 +1114,7 @@ break; case TOK_VAR: Stream_printf(f, "%*s", indent, ""); - instrument_expression(node, f); + output_expression(node, f, false); Stream_write_string(f, ";\n"); break; case TOK_RETURN: @@ -1105,7 +1123,7 @@ Stream_write_string(f, "return"); if (node->pn_kid != NULL) { Stream_write_char(f, ' '); - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, true); } Stream_write_string(f, ";\n"); break; @@ -1113,24 +1131,38 @@ assert(node->pn_arity == PN_UNARY); Stream_printf(f, "%*s", indent, ""); if (node->pn_kid != NULL) { - instrument_expression(node->pn_kid, f); + output_expression(node->pn_kid, f, true); } Stream_write_string(f, ";\n"); break; case TOK_COLON: + { assert(node->pn_arity == PN_NAME); - /* - This one is tricky: can't output instrumentation between the label and the - statement it's supposed to label ... - */ Stream_printf(f, "%*s", indent < 2? 0: indent - 2, ""); print_string_atom(node->pn_atom, f); Stream_write_string(f, ":\n"); - /* - ... use output_statement instead of instrument_statement. - */ - output_statement(node->pn_expr, f, indent, false); + JSParseNode * labelled = node->pn_expr; + if (labelled->pn_type == TOK_LEXICALSCOPE) { + labelled = labelled->pn_expr; + } + if (labelled->pn_type == TOK_LC) { + /* labelled block */ + Stream_printf(f, "%*s", indent, ""); + Stream_write_string(f, "{\n"); + instrument_statement(labelled, f, indent + 2, false); + Stream_printf(f, "%*s", indent, ""); + Stream_write_string(f, "}\n"); + } + else { + /* + This one is tricky: can't output instrumentation between the label and the + statement it's supposed to label, so use output_statement instead of + instrument_statement. + */ + output_statement(labelled, f, indent, false); + } break; + } case TOK_LEXICALSCOPE: /* let statement */ assert(node->pn_arity == PN_NAME); @@ -1173,7 +1205,7 @@ case PN_LIST: /* let definition */ Stream_printf(f, "%*s", indent, ""); - instrument_expression(node, f); + output_expression(node, f, false); Stream_write_string(f, ";\n"); break; default: @@ -1185,6 +1217,16 @@ Stream_printf(f, "%*s", indent, ""); Stream_write_string(f, "debugger;\n"); break; + case TOK_SEQ: + /* + This occurs with the statement: + for (var a = b in c) {} + */ + assert(node->pn_arity == PN_LIST); + for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { + instrument_statement(p, f, indent, false); + } + break; default: fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type); } @@ -1266,7 +1308,7 @@ } JS_SetErrorReporter(context, old_error_reporter); num_lines = node->pn_pos.end.lineno; - lines = xmalloc(num_lines); + lines = (char *) xmalloc(num_lines); for (unsigned int i = 0; i < num_lines; i++) { lines[i] = 0; } @@ -1350,7 +1392,8 @@ /* write line number info to the output */ Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n"); - if (jscoverage_mozilla) { + switch (jscoverage_mode) { + case JSCOVERAGE_MOZILLA: Stream_write_string(output, "try {\n"); Stream_write_string(output, " Components.utils.import('resource://gre/modules/jscoverage.jsm');\n"); Stream_printf(output, " dump('%s: successfully imported jscoverage module\\n');\n", id); @@ -1359,10 +1402,14 @@ Stream_write_string(output, " _$jscoverage = {};\n"); Stream_printf(output, " dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id); Stream_write_string(output, "}\n"); - } - else { + break; + case JSCOVERAGE_NORMAL: Stream_write_string(output, "if (! top._$jscoverage) {\n top._$jscoverage = {};\n}\n"); Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n"); + break; + case JSCOVERAGE_NO_BROWSER: + Stream_write_string(output, "if (typeof _$jscoverage === 'undefined') {\n var _$jscoverage = {};\n}\n"); + break; } Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id); Stream_printf(output, " _$jscoverage['%s'] = [];\n", file_id); @@ -1377,6 +1424,11 @@ free(exclusive_directives); exclusive_directives = NULL; + /* copy the original source to the output */ + Stream_printf(output, "_$jscoverage['%s'].source = ", file_id); + jscoverage_write_source(id, characters, num_characters, output); + Stream_printf(output, ";\n"); + /* conditionals */ if (has_conditionals) { Stream_printf(output, "_$jscoverage['%s'].conditionals = [];\n", file_id); @@ -1401,11 +1453,6 @@ free(if_directive); } - /* copy the original source to the output */ - Stream_printf(output, "_$jscoverage['%s'].source = ", file_id); - jscoverage_write_source(id, characters, num_characters, output); - Stream_printf(output, ";\n"); - Stream_delete(instrumented); file_id = NULL; @@ -1579,11 +1626,11 @@ }; static int compare_strings(const void * p1, const void * p2) { - return strcmp(p1, p2) == 0; + return strcmp((const char *) p1, (const char *) p2) == 0; } Coverage * Coverage_new(void) { - Coverage * result = xmalloc(sizeof(Coverage)); + Coverage * result = (Coverage *) xmalloc(sizeof(Coverage)); result->coverage_table = JS_NewHashTable(1024, JS_HashString, compare_strings, NULL, NULL, NULL); if (result->coverage_table == NULL) { fatal("cannot create hash table"); @@ -1618,8 +1665,8 @@ }; static intN enumerator(JSHashEntry * entry, intN i, void * arg) { - struct EnumeratorArg * enumerator_arg = arg; - enumerator_arg->f(entry->value, i, enumerator_arg->p); + struct EnumeratorArg * enumerator_arg = (struct EnumeratorArg *) arg; + enumerator_arg->f((FileCoverage *) entry->value, i, enumerator_arg->p); return 0; } @@ -1652,6 +1699,10 @@ } JSParseNode * root = js_ParseScript(context, global, &parse_context); free(parenthesized_json); + + JSParseNode * semi = NULL; + JSParseNode * object = NULL; + if (root == NULL) { result = -1; goto done; @@ -1662,21 +1713,14 @@ result = -1; goto done; } - JSParseNode * semi = root->pn_u.list.head; + semi = root->pn_u.list.head; /* the list must be TOK_SEMI and it must contain only one element */ if (semi->pn_type != TOK_SEMI || semi->pn_next != NULL) { result = -1; goto done; } - JSParseNode * parenthesized = semi->pn_kid; - - /* this must be a parenthesized expression */ - if (parenthesized->pn_type != TOK_RP) { - result = -1; - goto done; - } - JSParseNode * object = parenthesized->pn_kid; + object = semi->pn_kid; /* this must be an object literal */ if (object->pn_type != TOK_RC) { @@ -1760,11 +1804,11 @@ } /* look up the file in the coverage table */ - FileCoverage * file_coverage = JS_HashTableLookup(coverage->coverage_table, id_bytes); + FileCoverage * file_coverage = (FileCoverage *) JS_HashTableLookup(coverage->coverage_table, id_bytes); if (file_coverage == NULL) { /* not there: create a new one */ char * id = xstrdup(id_bytes); - file_coverage = xmalloc(sizeof(FileCoverage)); + file_coverage = (FileCoverage *) xmalloc(sizeof(FileCoverage)); file_coverage->id = id; file_coverage->num_coverage_lines = array->pn_count; file_coverage->coverage_lines = xnew(int, array->pn_count); @@ -1788,7 +1832,7 @@ /* add to the hash table */ JS_HashTableAdd(coverage->coverage_table, id, file_coverage); - struct FileCoverageList * coverage_list = xmalloc(sizeof(struct FileCoverageList)); + struct FileCoverageList * coverage_list = (FileCoverageList *) xmalloc(sizeof(struct FileCoverageList)); coverage_list->file_coverage = file_coverage; coverage_list->next = coverage->coverage_list; coverage->coverage_list = coverage_list;