Remove OP_BOUNDS in favor of an inline check.
Remove OP_BOUNDS in favor of an inline check.
1.1 --- a/src/BytecodeCompiler.cpp Sun Aug 05 01:10:49 2012 -0700
1.2 +++ b/src/BytecodeCompiler.cpp Sun Aug 05 01:15:35 2012 -0700
1.3 @@ -249,23 +249,14 @@
1.4 IndexExpression *index = node->lvalue()->toIndexExpression();
1.5 __ note_position(index->pos());
1.6
1.7 - // Note: Eventually, watch out for a hole here. An expression like:
1.8 - //
1.9 - // (a[4] = (5, a = []))
1.10 - //
1.11 - // Could shrink array, so we need to either bind a[i] to a Reference,
1.12 - // or keep the bounds check near the set. This is just a semantic
1.13 - // decision.
1.14 index->left()->accept(this);
1.15 index->right()->accept(this);
1.16
1.17 if (node->token() != TOK_ASSIGN)
1.18 __ dup2();
1.19
1.20 - if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray())) {
1.21 - __ bounds();
1.22 + if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
1.23 __ getelem(index->type());
1.24 - }
1.25 }
1.26
1.27 if (node->token() == TOK_ASSIGN) {
1.28 @@ -302,9 +293,6 @@
1.29 __ setfield(expr->fieldIndex(), expr->type());
1.30 } else {
1.31 IndexExpression *index = node->lvalue()->toIndexExpression();
1.32 - // :TODO: get rid of the BOUNDS instruction, embed it in g/setelem*?
1.33 - // We can't emit it here because the stack is slightly out of position.
1.34 - // __ bounds();
1.35 __ setelem(index->type());
1.36 }
1.37 }
1.38 @@ -382,7 +370,6 @@
1.39 index->right()->accept(this);
1.40
1.41 assert(!node->type()->isArray());
1.42 - __ bounds();
1.43 __ dup2();
1.44 __ getelem(node->type());
1.45
1.46 @@ -538,7 +525,6 @@
1.47 node->left()->accept(this);
1.48 node->right()->accept(this);
1.49 __ note_position(node->pos());
1.50 - __ bounds();
1.51 __ getelem(node->type());
1.52 }
1.53
1.54 @@ -887,7 +873,6 @@
1.55 expr->left()->accept(this);
1.56 expr->right()->accept(this);
1.57 __ note_position(expr->pos());
1.58 - __ bounds();
1.59 __ arrayref_lifo();
1.60 } else {
1.61 // We don't know how to, or can't, build a direct reference to
2.1 --- a/src/BytecodeEmitter.h Sun Aug 05 01:10:49 2012 -0700
2.2 +++ b/src/BytecodeEmitter.h Sun Aug 05 01:15:35 2012 -0700
2.3 @@ -430,10 +430,6 @@
2.4 writeUint32(var->slot());
2.5 }
2.6
2.7 - void bounds() {
2.8 - singleByteOp(OP_BOUNDS);
2.9 - markOop(2);
2.10 - }
2.11 void float_(float value) {
2.12 ensure(OP_FLOAT_LENGTH);
2.13 writeOp(OP_FLOAT);
3.1 --- a/src/Interpreter.cpp Sun Aug 05 01:10:49 2012 -0700
3.2 +++ b/src/Interpreter.cpp Sun Aug 05 01:15:35 2012 -0700
3.3 @@ -741,21 +741,16 @@
3.4 break;
3.5 }
3.6
3.7 -case OP_BOUNDS:
3.8 +case OP_GETELEM:
3.9 {
3.10 - Array *array = top.sp[-2].array;
3.11 + Array *array = Array::cast(top.sp[-2].obj);
3.12 int index = top.sp[-1].i32;
3.13 +
3.14 if (index < 0 || unsigned(index) >= array->length()) {
3.15 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
3.16 goto error;
3.17 }
3.18 - break;
3.19 -}
3.20
3.21 -case OP_GETELEM:
3.22 -{
3.23 - Array *array = Array::cast(top.sp[-2].obj);
3.24 - int index = top.sp[-1].i32;
3.25 GetElement(array, index, &top.sp[-2]);
3.26 top.sp--;
3.27 break;
3.28 @@ -765,6 +760,12 @@
3.29 {
3.30 Array *array = Array::cast(top.sp[-3].obj);
3.31 int index = top.sp[-2].i32;
3.32 +
3.33 + if (index < 0 || unsigned(index) >= array->length()) {
3.34 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
3.35 + goto error;
3.36 + }
3.37 +
3.38 SetElement(zone, array, index, top.sp[-1]);
3.39 top.sp[-3] = top.sp[-1];
3.40 top.sp -= 2;
4.1 --- a/src/Opcodes.cpp Sun Aug 05 01:10:49 2012 -0700
4.2 +++ b/src/Opcodes.cpp Sun Aug 05 01:15:35 2012 -0700
4.3 @@ -162,7 +162,6 @@
4.4 case OP_POP:
4.5 case OP_GETELEM:
4.6 case OP_SETELEM:
4.7 - case OP_BOUNDS:
4.8 case OP_SHL:
4.9 case OP_SHR:
4.10 case OP_USHR:
5.1 --- a/src/Opcodes.tbl Sun Aug 05 01:10:49 2012 -0700
5.2 +++ b/src/Opcodes.tbl Sun Aug 05 01:15:35 2012 -0700
5.3 @@ -125,73 +125,65 @@
5.4 OPDEF(OP_GETELEM, 42, "getelem", 1, 2, 1)
5.5 OPDEF(OP_SETELEM, 43, "setelem", 1, 3, 1)
5.6
5.7 -// Performs a bounds check on an unsafe array.
5.8 -//
5.9 -// index = pop()
5.10 -// array = pop()
5.11 -// push(array)
5.12 -// push(index)
5.13 -OPDEF(OP_BOUNDS, 44, "bounds", 1, 2, 2)
5.14 -
5.15 // Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
5.16 -OPDEF(OP_FLOAT, 45, "float", 5, 0, 1)
5.17 +OPDEF(OP_FLOAT, 44, "float", 5, 0, 1)
5.18
5.19 // Converts an integer to a 32-bit IEEE-754 floating point immediate.
5.20 -OPDEF(OP_CVT_I2F, 46, "cvt.i2f", 1, 1, 1)
5.21 +OPDEF(OP_CVT_I2F, 45, "cvt.i2f", 1, 1, 1)
5.22
5.23 // Stack transitions for these binary operators:
5.24 // rhs = pop()
5.25 // lhs = pop()
5.26 // push(lhs OP rhs)
5.27 -OPDEF(OP_ADD_F, 47, "add.f", 1, 2, 1)
5.28 -OPDEF(OP_SUB_F, 48, "sub.f", 1, 2, 1)
5.29 -OPDEF(OP_MUL_F, 49, "mul.f", 1, 2, 1)
5.30 -OPDEF(OP_DIV_F, 50, "div.f", 1, 2, 1)
5.31 +OPDEF(OP_ADD_F, 46, "add.f", 1, 2, 1)
5.32 +OPDEF(OP_SUB_F, 47, "sub.f", 1, 2, 1)
5.33 +OPDEF(OP_MUL_F, 48, "mul.f", 1, 2, 1)
5.34 +OPDEF(OP_DIV_F, 49, "div.f", 1, 2, 1)
5.35
5.36 -OPDEF(OP_LT_F, 51, "lt.f", 1, 2, 1)
5.37 -OPDEF(OP_LE_F, 52, "le.f", 1, 2, 1)
5.38 -OPDEF(OP_GE_F, 53, "ge.f", 1, 2, 1)
5.39 -OPDEF(OP_GT_F, 54, "gt.f", 1, 2, 1)
5.40 -OPDEF(OP_EQ_F, 55, "eq.f", 1, 2, 1)
5.41 -OPDEF(OP_NE_F, 56, "ne.f", 1, 2, 1)
5.42 +OPDEF(OP_LT_F, 50, "lt.f", 1, 2, 1)
5.43 +OPDEF(OP_LE_F, 51, "le.f", 1, 2, 1)
5.44 +OPDEF(OP_GE_F, 52, "ge.f", 1, 2, 1)
5.45 +OPDEF(OP_GT_F, 53, "gt.f", 1, 2, 1)
5.46 +OPDEF(OP_EQ_F, 54, "eq.f", 1, 2, 1)
5.47 +OPDEF(OP_NE_F, 55, "ne.f", 1, 2, 1)
5.48
5.49 -OPDEF(OP_NOT_F, 57, "not.f", 1, 1, 1)
5.50 -OPDEF(OP_NEG_F, 58, "neg.f", 1, 1, 1)
5.51 +OPDEF(OP_NOT_F, 56, "not.f", 1, 1, 1)
5.52 +OPDEF(OP_NEG_F, 57, "neg.f", 1, 1, 1)
5.53
5.54 // Bitwise operators.
5.55 -OPDEF(OP_SHL, 59, "shl", 1, 2, 1)
5.56 -OPDEF(OP_SHR, 60, "shr", 1, 2, 1)
5.57 -OPDEF(OP_USHR, 61, "ushr", 1, 2, 1)
5.58 -OPDEF(OP_BITAND, 62, "bitand", 1, 2, 1)
5.59 -OPDEF(OP_BITOR, 63, "bitor", 1, 2, 1)
5.60 -OPDEF(OP_BITXOR, 64, "bitxor", 1, 2, 1)
5.61 -OPDEF(OP_BITNOT, 65, "bitnot", 1, 1, 1)
5.62 +OPDEF(OP_SHL, 58, "shl", 1, 2, 1)
5.63 +OPDEF(OP_SHR, 59, "shr", 1, 2, 1)
5.64 +OPDEF(OP_USHR, 60, "ushr", 1, 2, 1)
5.65 +OPDEF(OP_BITAND, 61, "bitand", 1, 2, 1)
5.66 +OPDEF(OP_BITOR, 62, "bitor", 1, 2, 1)
5.67 +OPDEF(OP_BITXOR, 63, "bitxor", 1, 2, 1)
5.68 +OPDEF(OP_BITNOT, 64, "bitnot", 1, 1, 1)
5.69
5.70 // Saves or restores the position of the LIFO heap to/from a local slot.
5.71 -OPDEF(OP_SAVELIFO, 66, "savelifo", 5, 0, 0)
5.72 -OPDEF(OP_UNWINDLIFO, 67, "unwindlifo", 5, 0, 0)
5.73 +OPDEF(OP_SAVELIFO, 65, "savelifo", 5, 0, 0)
5.74 +OPDEF(OP_UNWINDLIFO, 66, "unwindlifo", 5, 0, 0)
5.75
5.76 // Composes a variable reference to a stack slot or argument.
5.77 -OPDEF(OP_VARREF_LIFO, 68, "varref.lifo", 5, 0, 1)
5.78 -OPDEF(OP_ARGREF_LIFO, 69, "argref.lifo", 5, 0, 1)
5.79 -OPDEF(OP_SLOTREF_LIFO, 70, "slotref.lifo", 1, 1, 1)
5.80 -OPDEF(OP_ARRAYREF_LIFO, 71, "arrayref.lifo",1, 2, 1)
5.81 -OPDEF(OP_GETREF_I, 72, "getref.i", 1, 1, 1)
5.82 -OPDEF(OP_SETREF_I, 73, "setref.i", 1, 2, 1)
5.83 -OPDEF(OP_GETREF_F, 74, "getref.f", 1, 1, 1)
5.84 -OPDEF(OP_SETREF_F, 75, "setref.f", 1, 2, 1)
5.85 +OPDEF(OP_VARREF_LIFO, 67, "varref.lifo", 5, 0, 1)
5.86 +OPDEF(OP_ARGREF_LIFO, 68, "argref.lifo", 5, 0, 1)
5.87 +OPDEF(OP_SLOTREF_LIFO, 69, "slotref.lifo", 1, 1, 1)
5.88 +OPDEF(OP_ARRAYREF_LIFO, 70, "arrayref.lifo",1, 2, 1)
5.89 +OPDEF(OP_GETREF_I, 71, "getref.i", 1, 1, 1)
5.90 +OPDEF(OP_SETREF_I, 72, "setref.i", 1, 2, 1)
5.91 +OPDEF(OP_GETREF_F, 73, "getref.f", 1, 1, 1)
5.92 +OPDEF(OP_SETREF_F, 74, "setref.f", 1, 2, 1)
5.93
5.94 // Pushes an object reference onto the stack.
5.95 -OPDEF(OP_OBJECT, 76, "object", 5, 0, 1)
5.96 +OPDEF(OP_OBJECT, 75, "object", 5, 0, 1)
5.97
5.98 // Duplicates the top item on the stack.
5.99 -OPDEF(OP_DUP, 77, "dup", 1, 1, 2)
5.100 +OPDEF(OP_DUP, 76, "dup", 1, 1, 2)
5.101
5.102 // Duplicates the top two items on the stack.
5.103 -OPDEF(OP_DUP2, 78, "dup2", 1, 2, 4)
5.104 +OPDEF(OP_DUP2, 77, "dup2", 1, 2, 4)
5.105
5.106 // Swaps the two items at the top of the stack.
5.107 -OPDEF(OP_SWAP, 79, "swap", 1, 2, 2)
5.108 +OPDEF(OP_SWAP, 78, "swap", 1, 2, 2)
5.109
5.110 // Roll operation is the same as Forth. It steals a value on the stack,
5.111 // shifting all stack values down, and then places the stolen value back at
5.112 @@ -201,14 +193,14 @@
5.113 // sp[-3] = sp[-2]
5.114 // sp[-2] = sp[-1]
5.115 // sp[-1] = p
5.116 -OPDEF(OP_ROLL3, 80, "roll3", 1, 3, 3)
5.117 +OPDEF(OP_ROLL3, 79, "roll3", 1, 3, 3)
5.118
5.119 // Pick operation is the same as Forth. It pushes a copy of a slot at a
5.120 // specific depth.
5.121 //
5.122 // push(sp[-n])
5.123 -OPDEF(OP_PICK2, 81, "pick2", 1, 2, 3)
5.124 -OPDEF(OP_PICK3, 82, "pick3", 1, 3, 4)
5.125 +OPDEF(OP_PICK2, 80, "pick2", 1, 2, 3)
5.126 +OPDEF(OP_PICK3, 81, "pick3", 1, 3, 4)
5.127
5.128 // Calls a native function. During the course of calling a native, arguments
5.129 // on the stack are re-pushed to match the cell-based native calling
5.130 @@ -219,51 +211,51 @@
5.131 //
5.132 // [u8 Opcode] [u32 Index] [u32 ArgCount]
5.133 //
5.134 -OPDEF(OP_CALLNATIVE, 83, "callnative", 9, -1, 1)
5.135 +OPDEF(OP_CALLNATIVE, 82, "callnative", 9, -1, 1)
5.136
5.137 // Returns from a function that does return a value.
5.138 -OPDEF(OP_RETURNVOID, 84, "returnvoid", 1, 0, 0)
5.139 +OPDEF(OP_RETURNVOID, 83, "returnvoid", 1, 0, 0)
5.140
5.141 // Loads the module of the running function.
5.142 -OPDEF(OP_MODULE, 85, "module", 1, 0, 1)
5.143 +OPDEF(OP_MODULE, 84, "module", 1, 0, 1)
5.144
5.145 // Loads a function from a module object. The operand is the slot number
5.146 // in the module.
5.147 -OPDEF(OP_GETMODULE_FN, 86, "getmodule.fn", 5, 1, 1)
5.148 +OPDEF(OP_GETMODULE_FN, 85, "getmodule.fn", 5, 1, 1)
5.149
5.150 // Opcodes for accessing an environment slot in the global scope.
5.151 -OPDEF(OP_SETGLOBAL_I, 87, "setglobal.i", 5, 1, 1)
5.152 -OPDEF(OP_SETGLOBAL_F, 88, "setglobal.f", 5, 1, 1)
5.153 -OPDEF(OP_SETGLOBAL_O, 89, "setglobal.o", 5, 1, 1)
5.154 -OPDEF(OP_GETGLOBAL_I, 90, "getglobal.i", 5, 0, 1)
5.155 -OPDEF(OP_GETGLOBAL_F, 91, "getglobal.f", 5, 0, 1)
5.156 -OPDEF(OP_GETGLOBAL_O, 92, "getglobal.o", 5, 0, 1)
5.157 +OPDEF(OP_SETGLOBAL_I, 86, "setglobal.i", 5, 1, 1)
5.158 +OPDEF(OP_SETGLOBAL_F, 87, "setglobal.f", 5, 1, 1)
5.159 +OPDEF(OP_SETGLOBAL_O, 88, "setglobal.o", 5, 1, 1)
5.160 +OPDEF(OP_GETGLOBAL_I, 89, "getglobal.i", 5, 0, 1)
5.161 +OPDEF(OP_GETGLOBAL_F, 90, "getglobal.f", 5, 0, 1)
5.162 +OPDEF(OP_GETGLOBAL_O, 91, "getglobal.o", 5, 0, 1)
5.163
5.164 // Reinterprets a 32-bit integer as a float, or vice-versa.
5.165 -OPDEF(OP_BITS_I2F, 93, "bits.i2f", 1, 1, 1)
5.166 -OPDEF(OP_BITS_F2I, 94, "bits.f2i", 1, 1, 1)
5.167 +OPDEF(OP_BITS_I2F, 92, "bits.i2f", 1, 1, 1)
5.168 +OPDEF(OP_BITS_F2I, 93, "bits.f2i", 1, 1, 1)
5.169
5.170 // Pushes a boolean value.
5.171 -OPDEF(OP_TRUE, 95, "true", 1, 0, 1)
5.172 -OPDEF(OP_FALSE, 96, "false", 1, 0, 1)
5.173 +OPDEF(OP_TRUE, 94, "true", 1, 0, 1)
5.174 +OPDEF(OP_FALSE, 95, "false", 1, 0, 1)
5.175
5.176 // Allocate a struct. The HeapTenure is stored as a byte following pc. The
5.177 // StructMap to use is specified as an index into the script's Map table.
5.178 //
5.179 // Format:
5.180 // [u8 op] [u32 index]
5.181 -OPDEF(OP_NEWSTRUCT, 97, "newstruct", 6, 0, 1)
5.182 +OPDEF(OP_NEWSTRUCT, 96, "newstruct", 6, 0, 1)
5.183
5.184 // Performs a struct-to-struct assignment.
5.185 // Left = pop()
5.186 // Right = pop()
5.187 // copy(Left, Right)
5.188 // push(Left)
5.189 -OPDEF(OP_COPYSTRUCT, 98, "structcopy", 1, 2, 1)
5.190 +OPDEF(OP_COPYSTRUCT, 97, "structcopy", 1, 2, 1)
5.191
5.192 // Sets or gets a property in a struct. The index of the field is specified as
5.193 // a 32-bit integer. Note that these opcodes follow a new style of deriving
5.194 // their types at runtime.
5.195 -OPDEF(OP_GETFIELD, 99, "getfield", 5, 1, 1)
5.196 -OPDEF(OP_SETFIELD, 100, "setfield", 5, 2, 1)
5.197 +OPDEF(OP_GETFIELD, 98, "getfield", 5, 1, 1)
5.198 +OPDEF(OP_SETFIELD, 99, "setfield", 5, 2, 1)
5.199