/[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 361 by siliconforks, Sun Oct 26 05:28:03 2008 UTC revision 375 by siliconforks, Tue Oct 28 05:30:01 2008 UTC
# Line 70  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 326  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 339  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 349  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      if (param == NULL) {      if (param == NULL) {
367        fatal("unsupported parameter type for function: %s", file_id);        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      }      }
     print_string_atom(param, f);  
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");
# Line 425  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 464  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 551  Line 607 
607        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
608        break;        break;
609      default:      default:
610        fatal("%s: unknown operator (%d) in file", file_id, node->pn_op);        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
611        break;        break;
612      }      }
613      break;      break;
# Line 599  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 must be parenthesized */
659        if (node->pn_expr->pn_type == TOK_NUMBER) {
660          Stream_write_char(f, '(');
661          instrument_expression(node->pn_expr, f);
662          Stream_write_char(f, ')');
663        }
664        else {
665          instrument_expression(node->pn_expr, f);
666        }
667      /*      /*
668      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'
669      contains illegal characters, we have to use the subscript syntax instead of      contains illegal characters, we have to use the subscript syntax instead of
670      the dot syntax.      the dot syntax.
671      */      */
     instrument_expression(node->pn_expr, f);  
672      assert(ATOM_IS_STRING(node->pn_atom));      assert(ATOM_IS_STRING(node->pn_atom));
673      {      {
674        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
# Line 661  Line 725 
725      Stream_write_char(f, '{');      Stream_write_char(f, '{');
726      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) {
727        if (p->pn_type != TOK_COLON) {        if (p->pn_type != TOK_COLON) {
728          fatal("unsupported node type in file %s: %d", file_id, p->pn_type);          fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
729        }        }
730        if (p != node->pn_head) {        if (p != node->pn_head) {
731          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
# Line 679  Line 743 
743          }          }
744          instrument_expression(p->pn_left, f);          instrument_expression(p->pn_left, f);
745          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
746            fatal("parse error: expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
747          }          }
748          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
749          break;          break;
# Line 805  Line 869 
869      instrument_declarations(node, f);      instrument_declarations(node, f);
870      break;      break;
871    default:    default:
872      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);
873    }    }
874  }  }
875    
# Line 834  Line 898 
898      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
899      if (! is_jscoverage_if) {      if (! is_jscoverage_if) {
900        if (line > num_lines) {        if (line > num_lines) {
901          fatal("%s: script contains more than 65,535 lines", file_id);          fatal("file %s contains more than 65,535 lines", file_id);
902        }        }
903        if (line >= 2 && exclusive_directives[line - 2]) {        if (line >= 2 && exclusive_directives[line - 2]) {
904          is_jscoverage_if = true;          is_jscoverage_if = true;
# Line 1130  Line 1194 
1194      Stream_write_string(f, "debugger;\n");      Stream_write_string(f, "debugger;\n");
1195      break;      break;
1196    default:    default:
1197      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);
1198    }    }
1199  }  }
1200    
# Line 1143  Line 1207 
1207    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {
1208      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
1209      if (line > num_lines) {      if (line > num_lines) {
1210        fatal("%s: script contains more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1211      }      }
1212    
1213      /* the root node has line number 0 */      /* the root node has line number 0 */
# Line 1191  Line 1255 
1255  }  }
1256    
1257  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {
1258    fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message);    warn_source(file_id, report->lineno, "%s", message);
1259  }  }
1260    
1261  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 1200  Line 1264 
1264    /* parse the javascript */    /* parse the javascript */
1265    JSParseContext parse_context;    JSParseContext parse_context;
1266    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)) {
1267      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file %s", file_id);
1268    }    }
1269    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);
1270    JSParseNode * node = js_ParseScript(context, global, &parse_context);    JSParseNode * node = js_ParseScript(context, global, &parse_context);
1271    if (node == NULL) {    if (node == NULL) {
1272      js_ReportUncaughtException(context);      js_ReportUncaughtException(context);
1273      fatal("parse error in file: %s", file_id);      fatal("parse error in file %s", file_id);
1274    }    }
1275    JS_SetErrorReporter(context, old_error_reporter);    JS_SetErrorReporter(context, old_error_reporter);
1276    num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
# Line 1227  Line 1291 
1291    size_t i = 0;    size_t i = 0;
1292    while (i < num_characters) {    while (i < num_characters) {
1293      if (line_number == UINT16_MAX) {      if (line_number == UINT16_MAX) {
1294        fatal("%s: script has more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1295      }      }
1296      line_number++;      line_number++;
1297      size_t line_start = i;      size_t line_start = i;

Legend:
Removed from v.361  
changed lines
  Added in v.375

  ViewVC Help
Powered by ViewVC 1.1.24