Commit ccb4f4e4 authored by coppro's avatar coppro

Script cleanup for standards-compliance (not going out of bounds on vectors).

I_POP is no longer considered a binary instruction because all other binary instructions expect the stack to have at least two elements - adding a manual check is kludgy
Added I_TAILCALL to accomodate indended optimizations
parent 281d3d58
......@@ -44,12 +44,15 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
try {
// Instruction pointer
const Instruction* instr = &script.instructions[0];
const Instruction* end = &*script.instructions.end();
const Instruction* end = instr + script.instructions.size();
// Loop until we are done
while (instr < end) {
// Evaluate the current instruction
Instruction i = *instr++;
// If a scope is created, destroy it at end of block.
scoped_ptr<LocalScope> scope;
switch (i.instr) {
case I_NOP: break;
// Push a constant
......@@ -59,7 +62,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
}
// Jump
case I_JUMP: {
instr = &script.instructions[i.data];
instr = &script.instructions[0] + i.data;
break;
}
// Conditional jump
......@@ -67,7 +70,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
bool condition = *stack.back();
stack.pop_back();
if (!condition) {
instr = &script.instructions[i.data];
instr = &script.instructions[0] + i.data;
}
break;
}
......@@ -98,7 +101,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
stack.push_back(val);
} else {
stack.erase(stack.end() - 2); // remove iterator
instr = &script.instructions[i.data];
instr = &script.instructions[0] + i.data;
}
break;
}
......@@ -112,7 +115,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
stack.push_back(key);
} else {
stack.erase(stack.end() - 2); // remove iterator
instr = &script.instructions[i.data];
instr = &script.instructions[0] + i.data;
}
break;
}
......@@ -123,9 +126,8 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
}
// Function call
case I_CALL: {
// new scope
LocalScope local_scope(*this);
case I_CALL: scope.reset(new LocalScope(*this)); //new scope
case I_TAILCALL: {
// prepare arguments
for (unsigned int j = 0 ; j < i.data ; ++j) {
setVariable((Variable)instr[i.data - j - 1].data, stack.back());
......@@ -203,6 +205,12 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
instrQuaternary(i.instr4, a, b, c, d);
break;
}
// Pop off stack
case I_POP: {
stack.pop_back();
break;
}
// Duplicate stack
case I_DUP: {
stack.push_back(stack.at(stack.size() - i.data - 1));
......@@ -419,9 +427,6 @@ class ScriptCompose : public ScriptValue {
void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& b) {
switch (i) {
case I_POP:
// a = a;
break;
case I_MEMBER:
a = a->getMember(*b);
break;
......
......@@ -169,7 +169,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
delete j;
}
if (instr >= &*script.instructions.end()) break; // end of script
if (instr >= &script.instructions[0] + script.instructions.size()) break; // end of script
// Analyze the current instruction
Instruction i = *instr++;
......@@ -182,11 +182,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
}
// Jump
case I_JUMP: {
if (&script.instructions[i.data] >= instr) {
if ( &script.instructions[0] + i.data >= instr) {
// forward jump
// create jump record
Jump* jump = new Jump;
jump->target = &script.instructions[i.data];
jump->target = &script.instructions[0] + i.data;
jump->stack_top.assign(stack.begin() + stack_size, stack.end());
getBindings(scope, jump->bindings);
jumps.push(jump);
......@@ -313,10 +313,6 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
}
// Simple instruction: binary
case I_BINARY: {
if (i.instr2 == I_POP) {
stack.pop_back();
continue;
}
ScriptValueP b = stack.back(); stack.pop_back();
ScriptValueP& a = stack.back();
switch (i.instr2) {
......@@ -356,6 +352,10 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
stack.push_back(stack.at(stack.size() - i.data - 1));
break;
}
// Pop value off stack
case I_POP: {
stack.pop_back();
}
}
}
......
......@@ -534,10 +534,10 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
expectToken(input, _("do")); // do
if (with_key) {
script.addInstruction(I_SET_VAR, key); // set key_name
script.addInstruction(I_BINARY, I_POP); // pop
script.addInstruction(I_POP); // pop
}
script.addInstruction(I_SET_VAR, var); // set name
script.addInstruction(I_BINARY, I_POP); // pop
script.addInstruction(I_POP); // pop
parseOper(input, script, PREC_SET, I_BINARY, I_ADD); // EEE; add
script.addInstruction(I_JUMP, lblStart); // jump lbl_start
script.comeFrom(lblStart); // lbl_end:
......@@ -650,7 +650,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
// allow ; at end of expression without errors
break;
}
script.addInstruction(I_BINARY, I_POP); // discard result of first expression
script.addInstruction(I_POP); // discard result of first expression
parseOper(input, script, PREC_SET);
} else if (minPrec <= PREC_SET && token==_(":=")) {
// We made a mistake, the part before the := should be a variable name,
......@@ -761,7 +761,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
// newline functions as ;
// only if we don't match another token!
input.putBack();
script.addInstruction(I_BINARY, I_POP);
script.addInstruction(I_POP);
parseOper(input, script, PREC_SET);
} else {
input.putBack();
......
......@@ -99,7 +99,11 @@ ScriptValueP Script::dependencies(Context& ctx, const Dependency& dep) const {
static const unsigned int INVALID_ADDRESS = 0x03FFFFFF;
unsigned int Script::addInstruction(InstructionType t) {
assert( t == I_JUMP || t == I_JUMP_IF_NOT || t == I_LOOP || t == I_LOOP_WITH_KEY);
assert( t == I_JUMP
|| t == I_JUMP_IF_NOT
|| t == I_LOOP
|| t == I_LOOP_WITH_KEY
|| t == I_POP);
Instruction i = {t, {INVALID_ADDRESS}};
instructions.push_back(i);
return getLabel() - 1;
......@@ -179,7 +183,6 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
break;
case I_BINARY: ret += _("binary\t");
switch (i.instr2) {
case I_POP: ret += _("pop"); break;
case I_ITERATOR_R: ret += _("iterator_r"); break;
case I_MEMBER: ret += _("member"); break;
case I_ADD: ret += _("+"); break;
......@@ -210,6 +213,8 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
}
break;
case I_DUP: ret += _("dup"); break;
case I_POP: ret += _("pop"); break;
case I_TAILCALL: ret += _("tailcall"); break;
}
// arg
switch (i.instr) {
......
......@@ -43,6 +43,8 @@ enum InstructionType
, I_TERNARY = 14 ///< arg = 3ary instr : pop 3 values, apply a function, push the result
, I_QUATERNARY = 15 ///< arg = 4ary instr : pop 4 values, apply a function, push the result
, I_DUP = 16 ///< arg = int : duplicate the k-from-top element of the stack
, I_POP = 17 ///< arg = * : pop the top value off the stack.
, I_TAILCALL = 18 ///< arg = int, n*var : perform a tail call - like I_CALL, except faster
};
/// Types of unary instructions (taking one argument from the stack)
......@@ -54,8 +56,7 @@ enum UnaryInstructionType
/// Types of binary instructions (taking two arguments from the stack)
enum BinaryInstructionType
{ I_POP ///< Pop the top value of the stack
, I_ITERATOR_R ///< Make an iterator for a range (two integers)
{ I_ITERATOR_R ///< Make an iterator for a range (two integers)
, I_MEMBER ///< Member of an object
// Arithmatic
, I_ADD ///< add
......
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