26 |
#include <stdlib.h> |
#include <stdlib.h> |
27 |
#include <string.h> |
#include <string.h> |
28 |
|
|
29 |
|
// needed by jsparse.h |
30 |
|
#include <jsbit.h> |
31 |
|
#include <jscntxt.h> |
32 |
|
#include <jsscript.h> |
33 |
|
|
34 |
#include <jsapi.h> |
#include <jsapi.h> |
35 |
#include <jsarena.h> |
#include <jsarena.h> |
36 |
#include <jsatom.h> |
#include <jsatom.h> |
354 |
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) { |
355 |
assert(node->pn_type == TOK_FUNCTION); |
assert(node->pn_type == TOK_FUNCTION); |
356 |
assert(node->pn_arity == PN_FUNC); |
assert(node->pn_arity == PN_FUNC); |
357 |
JSObject * object = node->pn_funpob->object; |
JSObject * object = node->pn_funbox->object; |
358 |
assert(JS_ObjectIsFunction(context, object)); |
assert(JS_ObjectIsFunction(context, object)); |
359 |
JSFunction * function = (JSFunction *) JS_GetPrivate(context, object); |
JSFunction * function = (JSFunction *) JS_GetPrivate(context, object); |
360 |
assert(function); |
assert(function); |
377 |
JSArenaPool pool; |
JSArenaPool pool; |
378 |
JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota); |
JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota); |
379 |
jsuword * local_names = NULL; |
jsuword * local_names = NULL; |
380 |
if (JS_GET_LOCAL_NAME_COUNT(function)) { |
if (function->hasLocalNames()) { |
381 |
local_names = js_GetLocalNameArray(context, function, &pool); |
local_names = js_GetLocalNameArray(context, function, &pool); |
382 |
if (local_names == NULL) { |
if (local_names == NULL) { |
383 |
fatal("out of memory"); |
fatal("out of memory"); |
391 |
JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]); |
JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]); |
392 |
if (param == NULL) { |
if (param == NULL) { |
393 |
destructuring = true; |
destructuring = true; |
394 |
|
|
395 |
|
JSParseNode * p = node->pn_body; |
396 |
|
if (p->pn_type == TOK_UPVARS) { |
397 |
|
assert(p->pn_arity == PN_NAMESET); |
398 |
|
p = p->pn_tree; |
399 |
|
} |
400 |
|
|
401 |
|
if (p->pn_type == TOK_ARGSBODY) { |
402 |
|
assert(p->pn_arity == PN_LIST); |
403 |
|
// the function body is the final element of the list |
404 |
|
for (p = p->pn_head; p->pn_next != NULL; p = p->pn_next) { |
405 |
|
; |
406 |
|
} |
407 |
|
} |
408 |
|
|
409 |
JSParseNode * expression = NULL; |
JSParseNode * expression = NULL; |
410 |
assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_SEQ); |
assert(p->pn_type == TOK_LC || p->pn_type == TOK_SEQ); |
411 |
JSParseNode * semi = node->pn_body->pn_head; |
assert(p->pn_arity == PN_LIST); |
412 |
|
JSParseNode * semi = p->pn_head; |
413 |
assert(semi->pn_type == TOK_SEMI); |
assert(semi->pn_type == TOK_SEMI); |
414 |
JSParseNode * comma = semi->pn_kid; |
JSParseNode * comma = semi->pn_kid; |
415 |
assert(comma->pn_type == TOK_COMMA); |
assert(comma->pn_type == TOK_COMMA); |
417 |
assert(p->pn_type == TOK_ASSIGN); |
assert(p->pn_type == TOK_ASSIGN); |
418 |
JSParseNode * rhs = p->pn_right; |
JSParseNode * rhs = p->pn_right; |
419 |
assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0); |
assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0); |
420 |
if (rhs->pn_slot == i) { |
if (UPVAR_FRAME_SLOT(rhs->pn_cookie) == i) { |
421 |
expression = p->pn_left; |
expression = p->pn_left; |
422 |
break; |
break; |
423 |
} |
} |
433 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
434 |
|
|
435 |
/* function body */ |
/* function body */ |
436 |
|
|
437 |
|
JSParseNode * p = node->pn_body; |
438 |
|
if (p->pn_type == TOK_UPVARS) { |
439 |
|
assert(p->pn_arity == PN_NAMESET); |
440 |
|
p = p->pn_tree; |
441 |
|
} |
442 |
|
|
443 |
|
if (p->pn_type == TOK_ARGSBODY) { |
444 |
|
assert(p->pn_arity == PN_LIST); |
445 |
|
// the function body is the final element of the list |
446 |
|
for (p = p->pn_head; p->pn_next != NULL; p = p->pn_next) { |
447 |
|
; |
448 |
|
} |
449 |
|
} |
450 |
|
|
451 |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
452 |
/* expression closure - use output_statement instead of instrument_statement */ |
/* expression closure - use output_statement instead of instrument_statement */ |
453 |
if (node->pn_body->pn_type == TOK_SEQ) { |
if (p->pn_type == TOK_SEQ) { |
454 |
assert(node->pn_body->pn_arity == PN_LIST); |
assert(p->pn_arity == PN_LIST); |
455 |
assert(node->pn_body->pn_count == 2); |
assert(p->pn_count == 2); |
456 |
output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false); |
output_statement(p->pn_head->pn_next, f, indent + 2, false); |
457 |
} |
} |
458 |
else { |
else { |
459 |
output_statement(node->pn_body, f, indent + 2, false); |
output_statement(p, f, indent + 2, false); |
460 |
} |
} |
461 |
} |
} |
462 |
else { |
else { |
463 |
assert(node->pn_body->pn_type == TOK_LC); |
assert(p->pn_type == TOK_LC); |
464 |
assert(node->pn_body->pn_arity == PN_LIST); |
assert(p->pn_arity == PN_LIST); |
465 |
JSParseNode * p = node->pn_body->pn_head; |
p = p->pn_head; |
466 |
if (destructuring) { |
if (destructuring) { |
467 |
p = p->pn_next; |
p = p->pn_next; |
468 |
} |
} |
489 |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
490 |
JSParseNode * function_node = node->pn_head; |
JSParseNode * function_node = node->pn_head; |
491 |
if (function_node->pn_type == TOK_FUNCTION) { |
if (function_node->pn_type == TOK_FUNCTION) { |
492 |
JSObject * object = function_node->pn_funpob->object; |
JSObject * object = function_node->pn_funbox->object; |
493 |
assert(JS_ObjectIsFunction(context, object)); |
assert(JS_ObjectIsFunction(context, object)); |
494 |
JSFunction * function = (JSFunction *) JS_GetPrivate(context, object); |
JSFunction * function = (JSFunction *) JS_GetPrivate(context, object); |
495 |
assert(function); |
assert(function); |
496 |
assert(object == &function->object); |
assert(object == &function->object); |
497 |
|
|
498 |
if (function_node->pn_flags & TCF_GENEXP_LAMBDA) { |
if (function_node->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) { |
499 |
/* it's a generator expression */ |
/* it's a generator expression */ |
500 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
501 |
output_array_comprehension_or_generator_expression(function_node->pn_body, f); |
JSParseNode * p = function_node->pn_body; |
502 |
|
if (p->pn_type == TOK_UPVARS) { |
503 |
|
assert(p->pn_arity == PN_NAMESET); |
504 |
|
p = p->pn_tree; |
505 |
|
} |
506 |
|
output_array_comprehension_or_generator_expression(p, f); |
507 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
508 |
return; |
return; |
509 |
} |
} |
518 |
if (p != list->pn_head) { |
if (p != list->pn_head) { |
519 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
520 |
} |
} |
521 |
output_expression(p, f, false); |
|
522 |
|
switch (p->pn_type) { |
523 |
|
case TOK_NAME: |
524 |
|
print_string_atom(p->pn_atom, f); |
525 |
|
if (p->pn_expr != NULL) { |
526 |
|
Stream_write_string(f, " = "); |
527 |
|
output_expression(p->pn_expr, f, false); |
528 |
|
} |
529 |
|
break; |
530 |
|
default: |
531 |
|
output_expression(p, f, false); |
532 |
|
break; |
533 |
|
} |
534 |
} |
} |
535 |
} |
} |
536 |
|
|
781 |
output_expression(p, f, false); |
output_expression(p, f, false); |
782 |
} |
} |
783 |
} |
} |
784 |
if (node->pn_extra == PNX_ENDCOMMA) { |
if (node->pn_xflags & PNX_ENDCOMMA) { |
785 |
Stream_write_char(f, ','); |
Stream_write_char(f, ','); |
786 |
} |
} |
787 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
835 |
break; |
break; |
836 |
case TOK_NAME: |
case TOK_NAME: |
837 |
print_string_atom(node->pn_atom, f); |
print_string_atom(node->pn_atom, f); |
|
if (node->pn_expr != NULL) { |
|
|
Stream_write_string(f, " = "); |
|
|
output_expression(node->pn_expr, f, false); |
|
|
} |
|
838 |
break; |
break; |
839 |
case TOK_STRING: |
case TOK_STRING: |
840 |
print_quoted_string_atom(node->pn_atom, f); |
print_quoted_string_atom(node->pn_atom, f); |
842 |
case TOK_REGEXP: |
case TOK_REGEXP: |
843 |
assert(node->pn_op == JSOP_REGEXP); |
assert(node->pn_op == JSOP_REGEXP); |
844 |
{ |
{ |
845 |
JSObject * object = node->pn_pob->object; |
JSObject * object = node->pn_objbox->object; |
846 |
jsval result; |
jsval result; |
847 |
js_regexp_toString(context, object, &result); |
js_regexp_toString(context, object, &result); |
848 |
print_regex(result, f); |
print_regex(result, f); |
1298 |
instrument_statement(p, f, indent, false); |
instrument_statement(p, f, indent, false); |
1299 |
} |
} |
1300 |
break; |
break; |
1301 |
|
case TOK_NAME: |
1302 |
|
// this is a duplicate function |
1303 |
|
JSParseNode function_node; |
1304 |
|
function_node.pn_type = TOK_FUNCTION; |
1305 |
|
function_node.pn_arity = PN_FUNC; |
1306 |
|
function_node.pn_funbox = node->pn_u.name.funbox2; |
1307 |
|
function_node.pn_expr = node->pn_u.name.expr2; |
1308 |
|
instrument_function(&function_node, f, indent, FUNCTION_NORMAL); |
1309 |
|
Stream_write_char(f, '\n'); |
1310 |
|
break; |
1311 |
default: |
default: |
1312 |
fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type); |
fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type); |
1313 |
} |
} |
1377 |
file_id = id; |
file_id = id; |
1378 |
|
|
1379 |
/* parse the javascript */ |
/* parse the javascript */ |
1380 |
JSParseContext parse_context; |
JSCompiler compiler(context); |
1381 |
if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) { |
if (! compiler.init(characters, num_characters, NULL, id, 1)) { |
1382 |
fatal("cannot create token stream from file %s", file_id); |
fatal("cannot create token stream from file %s", file_id); |
1383 |
} |
} |
1384 |
JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter); |
JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter); |
1385 |
JSParseNode * node = js_ParseScript(context, global, &parse_context); |
JSParseNode * node = compiler.parse(global); |
1386 |
if (node == NULL) { |
if (node == NULL) { |
1387 |
js_ReportUncaughtException(context); |
js_ReportUncaughtException(context); |
1388 |
fatal("parse error in file %s", file_id); |
fatal("parse error in file %s", file_id); |
1469 |
|
|
1470 |
Stream * instrumented = Stream_new(0); |
Stream * instrumented = Stream_new(0); |
1471 |
instrument_statement(node, instrumented, 0, false); |
instrument_statement(node, instrumented, 0, false); |
|
js_FinishParseContext(context, &parse_context); |
|
1472 |
|
|
1473 |
/* write line number info to the output */ |
/* write line number info to the output */ |
1474 |
Stream_write_string(output, JSCOVERAGE_INSTRUMENTED_HEADER); |
Stream_write_string(output, JSCOVERAGE_INSTRUMENTED_HEADER); |
1772 |
|
|
1773 |
JS_free(context, base); |
JS_free(context, base); |
1774 |
|
|
1775 |
JSParseContext parse_context; |
JSCompiler compiler(context); |
1776 |
if (! js_InitParseContext(context, &parse_context, NULL, NULL, parenthesized_json, length + 2, NULL, NULL, 1)) { |
if (! compiler.init(parenthesized_json, length + 2, NULL, NULL, 1)) { |
1777 |
free(parenthesized_json); |
free(parenthesized_json); |
1778 |
return -1; |
return -1; |
1779 |
} |
} |
1780 |
JSParseNode * root = js_ParseScript(context, global, &parse_context); |
JSParseNode * root = compiler.parse(global); |
1781 |
free(parenthesized_json); |
free(parenthesized_json); |
1782 |
|
|
1783 |
JSParseNode * semi = NULL; |
JSParseNode * semi = NULL; |
1966 |
} |
} |
1967 |
|
|
1968 |
done: |
done: |
|
js_FinishParseContext(context, &parse_context); |
|
1969 |
return result; |
return result; |
1970 |
} |
} |