From 0af211c56b29625b5254cd475208030c73015f23 Mon Sep 17 00:00:00 2001 From: "oliver@apple.com" Date: Tue, 24 Jun 2008 21:19:56 +0000 Subject: [PATCH] Groundwork for reimplementing the slow script dialog Reviewed by Cameron. Add special loop opcodes as groundwork for slow script termination. Also added a few assertions to prevent us from accidentally coalescing conditional jump operands in a way that might bypass the slow script opcodes. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@34777 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- JavaScriptCore/ChangeLog | 19 +++++++++++++ JavaScriptCore/VM/CodeGenerator.cpp | 7 +++-- JavaScriptCore/VM/LabelID.h | 1 + JavaScriptCore/VM/Machine.cpp | 53 +++++++++++++++++++++++++++++++++++-- JavaScriptCore/VM/Machine.h | 1 + JavaScriptCore/VM/Opcode.h | 2 ++ 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index d47e5a8b..c5a07db 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,22 @@ +2008-06-24 Oliver Hunt + + Reviewed by Cameron. + + Add special loop opcodes as groundwork for slow script + termination. Also added a few assertions to prevent us + from accidentally coalescing conditional jump operands + in a way that might bypass the slow script opcodes. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * VM/CodeGenerator.cpp: + (KJS::CodeGenerator::emitJumpIfTrueMayCombine): + (KJS::CodeGenerator::emitJumpScopes): + * VM/LabelID.h: + * VM/Machine.cpp: + (KJS::Machine::privateExecute): + * VM/Machine.h: + * VM/Opcode.h: + 2008-06-24 Darin Adler Reviewed by Cameron. diff --git a/JavaScriptCore/VM/CodeGenerator.cpp b/JavaScriptCore/VM/CodeGenerator.cpp index b5f3e5a..bfab3ee 100644 --- a/JavaScriptCore/VM/CodeGenerator.cpp +++ b/JavaScriptCore/VM/CodeGenerator.cpp @@ -420,6 +420,7 @@ void CodeGenerator::rewindBinaryOp() PassRefPtr CodeGenerator::emitJump(LabelID* target) { + ASSERT(target->isForwardLabel()); emitOpcode(op_jmp); instructions().append(target->offsetFrom(instructions().size())); return target; @@ -436,7 +437,7 @@ PassRefPtr CodeGenerator::emitJumpIfTrueMayCombine(RegisterID* cond, La if (cond->index() == dstIndex) { rewindBinaryOp(); - emitOpcode(op_jless); + emitOpcode(target->isForwardLabel() ? op_jless : op_loop_if_less); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->offsetFrom(instructions().size())); @@ -449,7 +450,7 @@ PassRefPtr CodeGenerator::emitJumpIfTrueMayCombine(RegisterID* cond, La PassRefPtr CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* target) { - emitOpcode(op_jtrue); + emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true); instructions().append(cond->index()); instructions().append(target->offsetFrom(instructions().size())); return target; @@ -457,6 +458,7 @@ PassRefPtr CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* tar PassRefPtr CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target) { + ASSERT(target->isForwardLabel()); emitOpcode(op_jfalse); instructions().append(cond->index()); instructions().append(target->offsetFrom(instructions().size())); @@ -1031,6 +1033,7 @@ PassRefPtr CodeGenerator::emitComplexJumpScopes(LabelID* target, Contro PassRefPtr CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth) { ASSERT(scopeDepth() - targetScopeDepth >= 0); + ASSERT(target->isForwardLabel()); size_t scopeDelta = scopeDepth() - targetScopeDepth; ASSERT(scopeDelta <= m_scopeContextStack.size()); diff --git a/JavaScriptCore/VM/LabelID.h b/JavaScriptCore/VM/LabelID.h index 6edb5e2..7153bb2 100644 --- a/JavaScriptCore/VM/LabelID.h +++ b/JavaScriptCore/VM/LabelID.h @@ -98,6 +98,7 @@ namespace KJS { return m_refCount; } + bool isForwardLabel() { return m_location == invalidLocation; } private: typedef Vector JumpVector; diff --git a/JavaScriptCore/VM/Machine.cpp b/JavaScriptCore/VM/Machine.cpp index 6c9640b..8f132bd 100644 --- a/JavaScriptCore/VM/Machine.cpp +++ b/JavaScriptCore/VM/Machine.cpp @@ -895,7 +895,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi Instruction* vPC = codeBlock->instructions.begin(); JSValue** k = codeBlock->jsValues.data(); Profiler** enabledProfilerReference = Profiler::enabledProfilerReference(); - + registerFile->setSafeForReentry(false); #define VM_CHECK_EXCEPTION() \ do { \ @@ -908,7 +908,9 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi #if DUMP_OPCODE_STATS OpcodeStats::resetLastInstruction(); #endif - + +#define CHECK_FOR_TIMEOUT() + #if HAVE(COMPUTED_GOTO) #define NEXT_OPCODE goto *vPC->u.opcode #if DUMP_OPCODE_STATS @@ -1887,6 +1889,26 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi vPC += target; NEXT_OPCODE; } + BEGIN_OPCODE(op_loop_if_true) { + /* loop_if_true cond(r) target(offset) + + Jumps to offset target from the current instruction, if and + only if register cond converts to boolean as true. + + Additionally this loop instruction may terminate JS execution is + the JS timeout is reached. + */ + int cond = (++vPC)->u.operand; + int target = (++vPC)->u.operand; + if (r[cond].u.jsValue->toBoolean(exec)) { + vPC += target; + CHECK_FOR_TIMEOUT(); + NEXT_OPCODE; + } + + ++vPC; + NEXT_OPCODE; + } BEGIN_OPCODE(op_jtrue) { /* jtrue cond(r) target(offset) @@ -1919,6 +1941,33 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi ++vPC; NEXT_OPCODE; } + BEGIN_OPCODE(op_loop_if_less) { + /* loop_if_less src1(r) src2(r) target(offset) + + Checks whether register src1 is less than register src2, as + with the ECMAScript '<' operator, and then jumps to offset + target from the current instruction, if and only if the + result of the comparison is true. + + Additionally this loop instruction may terminate JS execution is + the JS timeout is reached. + */ + JSValue* src1 = r[(++vPC)->u.operand].u.jsValue; + JSValue* src2 = r[(++vPC)->u.operand].u.jsValue; + int target = (++vPC)->u.operand; + + bool result = jsLess(exec, src1, src2); + VM_CHECK_EXCEPTION(); + + if (result) { + vPC += target; + CHECK_FOR_TIMEOUT(); + NEXT_OPCODE; + } + + ++vPC; + NEXT_OPCODE; + } BEGIN_OPCODE(op_jless) { /* jless src1(r) src2(r) target(offset) diff --git a/JavaScriptCore/VM/Machine.h b/JavaScriptCore/VM/Machine.h index 47cb033..0039e78 100644 --- a/JavaScriptCore/VM/Machine.h +++ b/JavaScriptCore/VM/Machine.h @@ -127,6 +127,7 @@ namespace KJS { bool isGlobalCallFrame(Register** registerBase, const Register* r) const { return (*registerBase) == r; } int m_reentryDepth; + #if HAVE(COMPUTED_GOTO) Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling HashMap m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling diff --git a/JavaScriptCore/VM/Opcode.h b/JavaScriptCore/VM/Opcode.h index a913222..3f459cc 100644 --- a/JavaScriptCore/VM/Opcode.h +++ b/JavaScriptCore/VM/Opcode.h @@ -97,6 +97,8 @@ namespace KJS { macro(op_jfalse) \ macro(op_jless) \ macro(op_jmp_scopes) \ + macro(op_loop_if_true) \ + macro(op_loop_if_less) \ \ macro(op_new_func) \ macro(op_new_func_exp) \ -- 1.8.3.1