From 8ce085e0c65e3de3b7a1c6fb586a197f9bf4432a Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Mon, 25 Aug 2008 17:12:41 -0400 Subject: [PATCH 1/3] Add test of (attempted) trace recording with an active call object --- js/src/trace-test.js | 23 +++++++++++++++++++ .../test-harness/xpcshell-simple/test_all.sh | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/js/src/trace-test.js b/js/src/trace-test.js index 05352bcfb49..4381104cf97 100644 --- a/js/src/trace-test.js +++ b/js/src/trace-test.js @@ -875,6 +875,29 @@ function forVarInWith() { forVarInWith.expected = "pqrst"; test(forVarInWith); +function addAccumulations(f) { + var a = f(); + var b = f(); + return a() + b(); +} + +function loopingAccumulator() { + var x = 0; + return function () { + for (var i = 0; i < 10; ++i) { + ++x; + } + return x; + } +} + +function testLoopingAccumulator() { + var x = addAccumulations(loopingAccumulator); + return x; +} +testLoopingAccumulator.expected = 20; +test(testLoopingAccumulator); + /* Keep these at the end so that we can see the summary after the trace-debug spew. */ print("\npassed:", passes.length && passes.join(",")); print("\nFAILED:", fails.length && fails.join(",")); diff --git a/tools/test-harness/xpcshell-simple/test_all.sh b/tools/test-harness/xpcshell-simple/test_all.sh index 671c8a4e40e..4249425e6c2 100755 --- a/tools/test-harness/xpcshell-simple/test_all.sh +++ b/tools/test-harness/xpcshell-simple/test_all.sh @@ -110,7 +110,8 @@ done for t in $testdir/test_*.js do - NATIVE_TOPSRCDIR="$native_topsrcdir" TOPSRCDIR="$topsrcdir" $xpcshell -s $headfiles -f $t $tailfiles 2> $t.log 1>&2 + echo "NATIVE_TOPSRCDIR=\"$native_topsrcdir\" TOPSRCDIR=\"$topsrcdir\" $xpcshell -j -s $headfiles -f $t $tailfiles 2> $t.log 1>&2" + NATIVE_TOPSRCDIR="$native_topsrcdir" TOPSRCDIR="$topsrcdir" $xpcshell -j -s $headfiles -f $t $tailfiles 2> $t.log 1>&2 rv="$?" if [ ! "$rv" = "0" -o \ `grep -c '\*\*\* PASS' $t.log` = 0 ] From 8a6d79d6b6c25eef6460781b29d148bc244a24a7 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 25 Aug 2008 14:34:26 -0700 Subject: [PATCH 2/3] Annotate gotos that are emitted for break statements with SRC_BREAK (452122, r=mrbkap). --- js/src/jsemit.cpp | 2 +- js/src/jsemit.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index f647b52e790..6b69c9ddf58 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -4664,7 +4664,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) ale = NULL; while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH) stmt = stmt->down; - noteType = SRC_NULL; + noteType = SRC_BREAK; } if (EmitGoto(cx, cg, stmt, &stmt->breaks, ale, noteType) < 0) diff --git a/js/src/jsemit.h b/js/src/jsemit.h index c416f4a3c47..d567272ee7f 100644 --- a/js/src/jsemit.h +++ b/js/src/jsemit.h @@ -563,6 +563,7 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); typedef enum JSSrcNoteType { SRC_NULL = 0, /* terminates a note vector */ SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */ + SRC_BREAK = 1, /* JSOP_GOTO is a break */ SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or to an index label in a regular (structuring) or a destructuring object initialiser */ From fc5667ef1305f74c30d18b446e6dc5458b3de464 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 25 Aug 2008 15:17:46 -0700 Subject: [PATCH 3/3] Split closeLoop() and compile() and add endLoop(), which omits an always-exit guard (will be used for break statements.) --- js/src/jstracer.cpp | 60 ++++++++++++++++++++++++++++----------------- js/src/jstracer.h | 2 ++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 983422c4e84..1e11b35457c 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1486,6 +1486,34 @@ TraceRecorder::isLoopHeader(JSContext* cx) const return cx->fp->regs->pc == fragment->root->ip; } +/* Compile the current fragment. */ +void +TraceRecorder::compile(Fragmento* fragmento) +{ + if (treeInfo->maxNativeStackSlots >= MAX_NATIVE_STACK_SLOTS) { + debug_only_v(printf("Trace rejected: excessive stack use.\n")); + fragment->blacklist(); + return; + } + ::compile(fragmento->assm(), fragment); + if (anchor) { + fragment->addLink(anchor); + fragmento->assm()->patch(anchor); + } + JS_ASSERT(fragment->code()); + JS_ASSERT(!fragment->vmprivate); + if (fragment == fragment->root) + fragment->vmprivate = treeInfo; + /* :TODO: windows support */ +#if defined DEBUG && !defined WIN32 + char* label = (char*)malloc(strlen(cx->fp->script->filename) + 64); + sprintf(label, "%s:%u", cx->fp->script->filename, + js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc)); + fragmento->labels->add(fragment, sizeof(Fragment), 0, label); + free(label); +#endif +} + /* Complete and compile a trace and link it to the existing tree if appropriate. */ void TraceRecorder::closeLoop(Fragmento* fragmento) @@ -1495,11 +1523,6 @@ TraceRecorder::closeLoop(Fragmento* fragmento) debug_only_v(printf("Trace rejected: unstable loop variables.\n");) return; } - if (treeInfo->maxNativeStackSlots >= MAX_NATIVE_STACK_SLOTS) { - debug_only_v(printf("Trace rejected: excessive stack use.\n")); - fragment->blacklist(); - return; - } SideExit *exit = snapshot(LOOP_EXIT); exit->target = fragment->root; if (fragment == fragment->root) { @@ -1507,23 +1530,16 @@ TraceRecorder::closeLoop(Fragmento* fragmento) } else { fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exit); } - compile(fragmento->assm(), fragment); - if (anchor) { - fragment->addLink(anchor); - fragmento->assm()->patch(anchor); - } - JS_ASSERT(fragment->code()); - JS_ASSERT(!fragment->vmprivate); - if (fragment == fragment->root) - fragment->vmprivate = treeInfo; - /* :TODO: windows support */ -#if defined DEBUG && !defined WIN32 - char* label = (char*)malloc(strlen(cx->fp->script->filename) + 64); - sprintf(label, "%s:%u", cx->fp->script->filename, - js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc)); - fragmento->labels->add(fragment, sizeof(Fragment), 0, label); - free(label); -#endif + compile(fragmento); +} + +/* Emit an always-exit guard and compile the tree (used for break statements. */ +void +TraceRecorder::endLoop(Fragmento* fragmento) +{ + SideExit *exit = snapshot(LOOP_EXIT); + fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exit); + compile(fragmento); } /* Emit code to adjust the stack to match the inner tree's stack expectations. */ diff --git a/js/src/jstracer.h b/js/src/jstracer.h index c3a0653e8cb..3e6ef7a476b 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -318,7 +318,9 @@ public: nanojit::SideExit* snapshot(nanojit::ExitType exitType); nanojit::Fragment* getFragment() const { return fragment; } bool isLoopHeader(JSContext* cx) const; + void compile(nanojit::Fragmento* fragmento); void closeLoop(nanojit::Fragmento* fragmento); + void endLoop(nanojit::Fragmento* fragmento); void blacklist() { fragment->blacklist(); } bool adjustCallerTypes(nanojit::Fragment* f); bool selectCallablePeerFragment(nanojit::Fragment** first);