/[jscoverage]/trunk/instrument-js.cpp
ViewVC logotype

Diff of /trunk/instrument-js.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 350 by siliconforks, Fri Oct 24 16:17:39 2008 UTC revision 377 by siliconforks, Tue Oct 28 05:30:43 2008 UTC
# Line 28  Line 28 
28  #include <jsapi.h>  #include <jsapi.h>
29  #include <jsarena.h>  #include <jsarena.h>
30  #include <jsatom.h>  #include <jsatom.h>
31    #include <jsemit.h>
32  #include <jsexn.h>  #include <jsexn.h>
33  #include <jsfun.h>  #include <jsfun.h>
34  #include <jsinterp.h>  #include <jsinterp.h>
# Line 51  Line 52 
52    struct IfDirective * next;    struct IfDirective * next;
53  };  };
54    
55    bool jscoverage_mozilla = false;
56    
57  static bool * exclusive_directives = NULL;  static bool * exclusive_directives = NULL;
58    
59  static JSRuntime * runtime = NULL;  static JSRuntime * runtime = NULL;
# Line 67  Line 70 
70  static uint16_t num_lines = 0;  static uint16_t num_lines = 0;
71    
72  void jscoverage_set_js_version(const char * version) {  void jscoverage_set_js_version(const char * version) {
73    js_version = atoi(version);    js_version = JS_StringToVersion(version);
74      if (js_version != JSVERSION_UNKNOWN) {
75        return;
76      }
77    
78      char * end;
79      js_version = (JSVersion) strtol(version, &end, 10);
80      if ((size_t) (end - version) != strlen(version)) {
81        fatal("invalid version: %s", version);
82      }
83  }  }
84    
85  void jscoverage_init(void) {  void jscoverage_init(void) {
# Line 276  Line 288 
288    Stream_write_char(f, ')');    Stream_write_char(f, ')');
289  }  }
290    
291    static void output_array_comprehension_or_generator_expression(JSParseNode * node, Stream * f) {
292      assert(node->pn_type == TOK_LEXICALSCOPE);
293      assert(node->pn_arity == PN_NAME);
294      JSParseNode * for_node = node->pn_expr;
295      assert(for_node->pn_type == TOK_FOR);
296      assert(for_node->pn_arity == PN_BINARY);
297      JSParseNode * p = for_node;
298      while (p->pn_type == TOK_FOR) {
299        p = p->pn_right;
300      }
301      JSParseNode * if_node = NULL;
302      if (p->pn_type == TOK_IF) {
303        if_node = p;
304        assert(if_node->pn_arity == PN_TERNARY);
305        p = if_node->pn_kid2;
306      }
307      assert(p->pn_arity == PN_UNARY);
308      p = p->pn_kid;
309      if (p->pn_type == TOK_YIELD) {
310        /* for generator expressions */
311        p = p->pn_kid;
312      }
313    
314      instrument_expression(p, f);
315      p = for_node;
316      while (p->pn_type == TOK_FOR) {
317        Stream_write_char(f, ' ');
318        output_for_in(p, f);
319        p = p->pn_right;
320      }
321      if (if_node) {
322        Stream_write_string(f, " if (");
323        instrument_expression(if_node->pn_kid1, f);
324        Stream_write_char(f, ')');
325      }
326    }
327    
328  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {
329    assert(node->pn_type == TOK_FUNCTION);    assert(node->pn_type == TOK_FUNCTION);
330    assert(node->pn_arity == PN_FUNC);    assert(node->pn_arity == PN_FUNC);
# Line 286  Line 335 
335    assert(object == &function->object);    assert(object == &function->object);
336    Stream_printf(f, "%*s", indent, "");    Stream_printf(f, "%*s", indent, "");
337    if (type == FUNCTION_NORMAL) {    if (type == FUNCTION_NORMAL) {
338      Stream_write_string(f, "function");      Stream_write_string(f, "function ");
339    }    }
340    
341    /* function name */    /* function name */
342    if (function->atom) {    if (function->atom) {
     Stream_write_char(f, ' ');  
343      print_string_atom(function->atom, f);      print_string_atom(function->atom, f);
344    }    }
345    
# Line 299  Line 347 
347    function parameters - see JS_DecompileFunction in jsapi.cpp, which calls    function parameters - see JS_DecompileFunction in jsapi.cpp, which calls
348    js_DecompileFunction in jsopcode.cpp    js_DecompileFunction in jsopcode.cpp
349    */    */
350    Stream_write_string(f, "(");    Stream_write_char(f, '(');
351    JSArenaPool pool;    JSArenaPool pool;
352    JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);    JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);
353    jsuword * local_names = NULL;    jsuword * local_names = NULL;
# Line 309  Line 357 
357        fatal("out of memory");        fatal("out of memory");
358      }      }
359    }    }
360      bool destructuring = false;
361    for (int i = 0; i < function->nargs; i++) {    for (int i = 0; i < function->nargs; i++) {
362      if (i > 0) {      if (i > 0) {
363        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
364      }      }
365      JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);      JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);
366      print_string_atom(param, f);      if (param == NULL) {
367          destructuring = true;
368          JSParseNode * expression = NULL;
369          assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY);
370          JSParseNode * semi = node->pn_body->pn_head;
371          assert(semi->pn_type == TOK_SEMI);
372          JSParseNode * comma = semi->pn_kid;
373          assert(comma->pn_type == TOK_COMMA);
374          for (JSParseNode * p = comma->pn_head; p != NULL; p = p->pn_next) {
375            assert(p->pn_type == TOK_ASSIGN);
376            JSParseNode * rhs = p->pn_right;
377            assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0);
378            if (rhs->pn_slot == i) {
379              expression = p->pn_left;
380              break;
381            }
382          }
383          assert(expression != NULL);
384          instrument_expression(expression, f);
385        }
386        else {
387          print_string_atom(param, f);
388        }
389    }    }
390    JS_FinishArenaPool(&pool);    JS_FinishArenaPool(&pool);
391    Stream_write_string(f, ") {\n");    Stream_write_string(f, ") {\n");
392    
393    /* function body */    /* function body */
394    if (function->flags & JSFUN_EXPR_CLOSURE) {    if (function->flags & JSFUN_EXPR_CLOSURE) {
395      /* expression closure */      /* expression closure - use output_statement instead of instrument_statement */
396      output_statement(node->pn_body, f, indent + 2, false);      if (node->pn_body->pn_type == TOK_BODY) {
397          assert(node->pn_body->pn_arity == PN_LIST);
398          assert(node->pn_body->pn_count == 2);
399          output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false);
400        }
401        else {
402          output_statement(node->pn_body, f, indent + 2, false);
403        }
404    }    }
405    else {    else {
406      instrument_statement(node->pn_body, f, indent + 2, false);      assert(node->pn_body->pn_type == TOK_LC);
407        assert(node->pn_body->pn_arity == PN_LIST);
408        JSParseNode * p = node->pn_body->pn_head;
409        if (destructuring) {
410          p = p->pn_next;
411        }
412        for (; p != NULL; p = p->pn_next) {
413          instrument_statement(p, f, indent + 2, false);
414        }
415    }    }
416    
417    Stream_write_string(f, "}\n");    Stream_write_string(f, "}\n");
418  }  }
419    
420  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
421    if (node->pn_head->pn_type == TOK_FUNCTION) {    JSParseNode * function_node = node->pn_head;
422      /* it's a generator expression */    if (function_node->pn_type == TOK_FUNCTION) {
423      JSParseNode * function_node = node->pn_head;      JSObject * object = function_node->pn_funpob->object;
424      JSParseNode * lexical_scope_node = function_node->pn_body;      assert(JS_ObjectIsFunction(context, object));
425      assert(lexical_scope_node->pn_type == TOK_LEXICALSCOPE);      JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);
426      assert(lexical_scope_node->pn_arity == PN_NAME);      assert(function);
427      JSParseNode * for_node = lexical_scope_node->pn_body;      assert(object == &function->object);
428      assert(for_node->pn_type == TOK_FOR);  
429      assert(for_node->pn_arity == PN_BINARY);      if (function_node->pn_flags & TCF_GENEXP_LAMBDA) {
430      JSParseNode * if_node = NULL;        /* it's a generator expression */
431      JSParseNode * semi_node;        Stream_write_char(f, '(');
432      switch (for_node->pn_right->pn_type) {        output_array_comprehension_or_generator_expression(function_node->pn_body, f);
433      case TOK_SEMI:        Stream_write_char(f, ')');
434        semi_node = for_node->pn_right;        return;
       break;  
     case TOK_IF:  
       if_node = for_node->pn_right;  
       assert(if_node->pn_arity == PN_TERNARY);  
       semi_node = if_node->pn_kid2;  
       assert(semi_node->pn_type == TOK_SEMI);  
       break;  
     default:  
       abort();  
       break;  
435      }      }
436      assert(semi_node->pn_arity == PN_UNARY);      else {
437      JSParseNode * yield_node = semi_node->pn_kid;        Stream_write_char(f, '(');
438      assert(yield_node->pn_type == TOK_YIELD);        instrument_expression(function_node, f);
     Stream_write_char(f, '(');  
     instrument_expression(yield_node->pn_kid, f);  
     Stream_write_char(f, ' ');  
     output_for_in(for_node, f);  
     if (if_node) {  
       Stream_write_string(f, " if (");  
       instrument_expression(if_node->pn_kid1, f);  
439        Stream_write_char(f, ')');        Stream_write_char(f, ')');
440      }      }
     Stream_write_char(f, ')');  
441    }    }
442    else {    else {
443      instrument_expression(node->pn_head, f);      instrument_expression(function_node, f);
444      Stream_write_char(f, '(');    }
445      for (struct JSParseNode * p = node->pn_head->pn_next; p != NULL; p = p->pn_next) {    Stream_write_char(f, '(');
446        if (p != node->pn_head->pn_next) {    for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) {
447          Stream_write_string(f, ", ");      if (p != node->pn_head->pn_next) {
448        }        Stream_write_string(f, ", ");
       instrument_expression(p, f);  
449      }      }
450      Stream_write_char(f, ')');      instrument_expression(p, f);
451    }    }
452      Stream_write_char(f, ')');
453  }  }
454    
455  static void instrument_declarations(JSParseNode * list, Stream * f) {  static void instrument_declarations(JSParseNode * list, Stream * f) {
# Line 400  Line 468 
468        }        }
469        break;        break;
470      case TOK_ASSIGN:      case TOK_ASSIGN:
471          /* destructuring */
472          instrument_expression(p->pn_left, f);
473          Stream_write_string(f, " = ");
474          instrument_expression(p->pn_right, f);
475          break;
476      case TOK_RB:      case TOK_RB:
477      case TOK_RC:      case TOK_RC:
478        /* destructuring */        /* destructuring */
# Line 439  Line 512 
512      }      }
513      break;      break;
514    case TOK_ASSIGN:    case TOK_ASSIGN:
515      instrument_expression(node->pn_left, f);      if (node->pn_left->pn_type == TOK_RC) {
516          /* destructuring assignment with object literal must be in parentheses */
517          Stream_write_char(f, '(');
518          instrument_expression(node->pn_left, f);
519          Stream_write_char(f, ')');
520        }
521        else {
522          instrument_expression(node->pn_left, f);
523        }
524      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
525      switch (node->pn_op) {      switch (node->pn_op) {
526      case JSOP_ADD:      case JSOP_ADD:
# Line 526  Line 607 
607        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
608        break;        break;
609      default:      default:
610        abort();        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
611        break;        break;
612      }      }
613      break;      break;
# Line 574  Line 655 
655      instrument_expression(node->pn_kid, f);      instrument_expression(node->pn_kid, f);
656      break;      break;
657    case TOK_DOT:    case TOK_DOT:
658        /* numeric literals, object literals must be parenthesized */
659        switch (node->pn_expr->pn_type) {
660        case TOK_NUMBER:
661        case TOK_RC:
662          Stream_write_char(f, '(');
663          instrument_expression(node->pn_expr, f);
664          Stream_write_char(f, ')');
665          break;
666        default:
667          instrument_expression(node->pn_expr, f);
668          break;
669        }
670      /*      /*
671      This may have originally been x['foo-bar'].  Because the string 'foo-bar'      This may have originally been x['foo-bar'].  Because the string 'foo-bar'
672      contains illegal characters, we have to use the subscript syntax instead of      contains illegal characters, we have to use the subscript syntax instead of
673      the dot syntax.      the dot syntax.
674      */      */
     instrument_expression(node->pn_expr, f);  
675      assert(ATOM_IS_STRING(node->pn_atom));      assert(ATOM_IS_STRING(node->pn_atom));
676      {      {
677        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
# Line 635  Line 727 
727    case TOK_RC:    case TOK_RC:
728      Stream_write_char(f, '{');      Stream_write_char(f, '{');
729      for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {      for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
730        assert(p->pn_type == TOK_COLON);        if (p->pn_type != TOK_COLON) {
731            fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
732          }
733        if (p != node->pn_head) {        if (p != node->pn_head) {
734          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
735        }        }
# Line 652  Line 746 
746          }          }
747          instrument_expression(p->pn_left, f);          instrument_expression(p->pn_left, f);
748          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
749            fatal("parse error: expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
750          }          }
751          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
752          break;          break;
# Line 741  Line 835 
835      break;      break;
836    case TOK_YIELD:    case TOK_YIELD:
837      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
838      Stream_write_string(f, "yield ");      Stream_write_string(f, "yield");
839      instrument_expression(node->pn_kid, f);      if (node->pn_kid != NULL) {
840          Stream_write_char(f, ' ');
841          instrument_expression(node->pn_kid, f);
842        }
843      break;      break;
844    case TOK_ARRAYCOMP:    case TOK_ARRAYCOMP:
845      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
# Line 759  Line 856 
856          abort();          abort();
857          break;          break;
858        }        }
       assert(block_node->pn_type == TOK_LEXICALSCOPE);  
       assert(block_node->pn_arity == PN_NAME);  
       JSParseNode * for_node = block_node->pn_expr;  
       assert(for_node->pn_type == TOK_FOR);  
       assert(for_node->pn_arity == PN_BINARY);  
       JSParseNode * if_node = NULL;  
       JSParseNode * push_node;  
       switch (for_node->pn_right->pn_type) {  
       case TOK_ARRAYPUSH:  
         push_node = for_node->pn_right;  
         assert(push_node->pn_arity == PN_UNARY);  
         break;  
       case TOK_IF:  
         if_node = for_node->pn_right;  
         assert(if_node->pn_arity == PN_TERNARY);  
         push_node = if_node->pn_kid2;  
         break;  
       default:  
         abort();  
         break;  
       }  
859        Stream_write_char(f, '[');        Stream_write_char(f, '[');
860        instrument_expression(push_node->pn_kid, f);        output_array_comprehension_or_generator_expression(block_node, f);
       Stream_write_char(f, ' ');  
       output_for_in(for_node, f);  
       if (if_node) {  
         Stream_write_string(f, " if (");  
         instrument_expression(if_node->pn_kid1, f);  
         Stream_write_char(f, ')');  
       }  
861        Stream_write_char(f, ']');        Stream_write_char(f, ']');
862      }      }
863      break;      break;
# Line 803  Line 872 
872      instrument_declarations(node, f);      instrument_declarations(node, f);
873      break;      break;
874    default:    default:
875      fatal("unsupported node type in file %s: %d", file_id, node->pn_type);      fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
876    }    }
877  }  }
878    
# Line 832  Line 901 
901      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
902      if (! is_jscoverage_if) {      if (! is_jscoverage_if) {
903        if (line > num_lines) {        if (line > num_lines) {
904          fatal("%s: script contains more than 65,535 lines", file_id);          fatal("file %s contains more than 65,535 lines", file_id);
905        }        }
906        if (line >= 2 && exclusive_directives[line - 2]) {        if (line >= 2 && exclusive_directives[line - 2]) {
907          is_jscoverage_if = true;          is_jscoverage_if = true;
# Line 1060  Line 1129 
1129      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1130      break;      break;
1131    case TOK_COLON:    case TOK_COLON:
1132      {
1133      assert(node->pn_arity == PN_NAME);      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 ...  
     */  
1134      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
1135      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
1136      Stream_write_string(f, ":\n");      Stream_write_string(f, ":\n");
1137      /*      JSParseNode * labelled = node->pn_expr;
1138      ... use output_statement instead of instrument_statement.      if (labelled->pn_type == TOK_LEXICALSCOPE) {
1139      */        labelled = labelled->pn_expr;
1140      output_statement(node->pn_expr, f, indent, false);      }
1141        if (labelled->pn_type == TOK_LC) {
1142          /* labelled block */
1143          Stream_printf(f, "%*s", indent, "");
1144          Stream_write_string(f, "{\n");
1145          instrument_statement(labelled, f, indent + 2, false);
1146          Stream_printf(f, "%*s", indent, "");
1147          Stream_write_string(f, "}\n");
1148        }
1149        else {
1150          /*
1151          This one is tricky: can't output instrumentation between the label and the
1152          statement it's supposed to label, so use output_statement instead of
1153          instrument_statement.
1154          */
1155          output_statement(labelled, f, indent, false);
1156        }
1157      break;      break;
1158      }
1159    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
1160      /* let statement */      /* let statement */
1161      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 1128  Line 1211 
1211      Stream_write_string(f, "debugger;\n");      Stream_write_string(f, "debugger;\n");
1212      break;      break;
1213    default:    default:
1214      fatal("unsupported node type in file %s: %d", file_id, node->pn_type);      fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
1215    }    }
1216  }  }
1217    
# Line 1141  Line 1224 
1224    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {
1225      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
1226      if (line > num_lines) {      if (line > num_lines) {
1227        fatal("%s: script contains more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1228      }      }
1229    
1230      /* the root node has line number 0 */      /* the root node has line number 0 */
# Line 1189  Line 1272 
1272  }  }
1273    
1274  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {
1275    fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message);    warn_source(file_id, report->lineno, "%s", message);
1276  }  }
1277    
1278  void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) {  void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) {
# Line 1198  Line 1281 
1281    /* parse the javascript */    /* parse the javascript */
1282    JSParseContext parse_context;    JSParseContext parse_context;
1283    if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) {    if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) {
1284      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file %s", file_id);
1285    }    }
1286    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);
1287    JSParseNode * node = js_ParseScript(context, global, &parse_context);    JSParseNode * node = js_ParseScript(context, global, &parse_context);
1288    if (node == NULL) {    if (node == NULL) {
1289      js_ReportUncaughtException(context);      js_ReportUncaughtException(context);
1290      fatal("parse error in file: %s", file_id);      fatal("parse error in file %s", file_id);
1291    }    }
1292    JS_SetErrorReporter(context, old_error_reporter);    JS_SetErrorReporter(context, old_error_reporter);
1293    num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
# Line 1225  Line 1308 
1308    size_t i = 0;    size_t i = 0;
1309    while (i < num_characters) {    while (i < num_characters) {
1310      if (line_number == UINT16_MAX) {      if (line_number == UINT16_MAX) {
1311        fatal("%s: script has more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1312      }      }
1313      line_number++;      line_number++;
1314      size_t line_start = i;      size_t line_start = i;
# Line 1292  Line 1375 
1375    
1376    /* write line number info to the output */    /* write line number info to the output */
1377    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");
1378    Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");    if (jscoverage_mozilla) {
1379    Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");      Stream_write_string(output, "try {\n");
1380        Stream_write_string(output, "  Components.utils.import('resource://gre/modules/jscoverage.jsm');\n");
1381        Stream_printf(output, "  dump('%s: successfully imported jscoverage module\\n');\n", id);
1382        Stream_write_string(output, "}\n");
1383        Stream_write_string(output, "catch (e) {\n");
1384        Stream_write_string(output, "  _$jscoverage = {};\n");
1385        Stream_printf(output, "  dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id);
1386        Stream_write_string(output, "}\n");
1387      }
1388      else {
1389        Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");
1390        Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");
1391      }
1392    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);
1393    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);
1394    for (int i = 0; i < num_lines; i++) {    for (int i = 0; i < num_lines; i++) {

Legend:
Removed from v.350  
changed lines
  Added in v.377

  ViewVC Help
Powered by ViewVC 1.1.24