Commit 3301ed8d authored by oliver@apple.com's avatar oliver@apple.com

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: http://svn.webkit.org/repository/webkit/trunk@34777 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent e1d57dbb
2008-06-24 Oliver Hunt <oliver@apple.com>
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 <darin@apple.com>
Reviewed by Cameron.
......
......@@ -420,6 +420,7 @@ void CodeGenerator::rewindBinaryOp()
PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target)
{
ASSERT(target->isForwardLabel());
emitOpcode(op_jmp);
instructions().append(target->offsetFrom(instructions().size()));
return target;
......@@ -436,7 +437,7 @@ PassRefPtr<LabelID> 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<LabelID> CodeGenerator::emitJumpIfTrueMayCombine(RegisterID* cond, La
PassRefPtr<LabelID> 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<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* tar
PassRefPtr<LabelID> 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<LabelID> CodeGenerator::emitComplexJumpScopes(LabelID* target, Contro
PassRefPtr<LabelID> CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth)
{
ASSERT(scopeDepth() - targetScopeDepth >= 0);
ASSERT(target->isForwardLabel());
size_t scopeDelta = scopeDepth() - targetScopeDepth;
ASSERT(scopeDelta <= m_scopeContextStack.size());
......
......@@ -98,6 +98,7 @@ namespace KJS {
return m_refCount;
}
bool isForwardLabel() { return m_location == invalidLocation; }
private:
typedef Vector<int, 8> JumpVector;
......
......@@ -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)
......
......@@ -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<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
......
......@@ -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) \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment