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