summaryrefslogtreecommitdiffhomepage
path: root/eval.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-12-02 20:21:27 +0100
committerJo-Philipp Wich <jo@mein.io>2020-12-06 16:49:10 +0100
commit30d3682b7a35496110044bfe2c02a48eedf52a9f (patch)
tree35a7c64000f9b0dc1930ee760dbe7117afb6afe7 /eval.c
parent7caf3331ba7d8f0dd91659e4001c9d8256bf4558 (diff)
treewide: prevent stale pointer access in opcode handlers
Instead of obtaining and caching direct opcode pointers, use relative references when dealing with opcodes since direct or indirect calls to uc_execute_op() might lead to reallocations of the opcode array, shifting memory addresses and invalidating pointers taken before the invocation. Such stale pointer accesses could be commonly triggered when one part of the processed expression was a require() or include() call loading relatively large ucode sources. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c416
1 files changed, 201 insertions, 215 deletions
diff --git a/eval.c b/eval.c
index 3473235..2f7d968 100644
--- a/eval.c
+++ b/eval.c
@@ -145,15 +145,15 @@ uc_execute_list(struct uc_state *state, uint32_t off);
static char *
uc_ref_to_str(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- struct uc_op *op2 = uc_get_child(state, off, 1);
+ int child_type = OPn_TYPE(off, 1);
+ int op_type = OP_TYPE(off);
const char *l;
char *s, *p;
- switch (op ? op->type : 0) {
+ switch (op_type) {
case T_DOT:
- s = uc_ref_to_str(state, op->tree.operand[0]);
- l = ((op2 ? op2->type : 0) == T_LABEL) ? json_object_get_string(op2->val) : "???";
+ s = uc_ref_to_str(state, OPn(off, 0));
+ l = (child_type == T_LABEL) ? json_object_get_string(OPn_VAL(off, 1)) : "???";
if (asprintf(&p, "%s.%s", s ? s : "(...)", l) == -1)
p = NULL;
@@ -163,23 +163,23 @@ uc_ref_to_str(struct uc_state *state, uint32_t off)
return p;
case T_LBRACK:
- if (!op->is_postfix)
+ if (!OP_IS_POSTFIX(off))
return NULL;
/* fall through */
case T_LPAREN:
- s = uc_ref_to_str(state, op->tree.operand[0]);
+ s = uc_ref_to_str(state, OPn(off, 0));
- switch (op2 ? op2->type : 0) {
+ switch (child_type) {
case T_STRING:
- l = json_object_to_json_string_ext(op2->val, JSON_C_TO_STRING_NOSLASHESCAPE);
+ l = json_object_to_json_string_ext(OPn_VAL(off, 1), JSON_C_TO_STRING_NOSLASHESCAPE);
break;
case T_NUMBER:
case T_LABEL:
case T_BOOL:
- l = json_object_get_string(op2->val);
+ l = json_object_get_string(OPn_VAL(off, 1));
break;
default:
@@ -187,8 +187,8 @@ uc_ref_to_str(struct uc_state *state, uint32_t off)
}
if (asprintf(&p, "%s%c%s%c", s ? s : "(...)",
- (op->type == T_LPAREN) ? '(' : '[', l,
- (op->type == T_LPAREN) ? ')' : ']') == -1)
+ (op_type == T_LPAREN) ? '(' : '[', l,
+ (op_type == T_LPAREN) ? ')' : ']') == -1)
p = NULL;
free(s);
@@ -196,7 +196,7 @@ uc_ref_to_str(struct uc_state *state, uint32_t off)
return p;
case T_LABEL:
- return strdup(json_object_get_string(op->val));
+ return strdup(json_object_get_string(OP_VAL(off)));
default:
return NULL;
@@ -206,22 +206,22 @@ uc_ref_to_str(struct uc_state *state, uint32_t off)
static struct json_object *
uc_getref(struct uc_state *state, uint32_t off, struct json_object **key)
{
- struct uc_op *op = uc_get_op(state, off);
- uint32_t off1 = op ? op->tree.operand[0] : 0;
- uint32_t off2 = op ? op->tree.operand[1] : 0;
+ uint32_t off1 = OPn(off, 0);
+ uint32_t off2 = OPn(off, 1);
+ int type = OP_TYPE(off);
struct uc_scope *sc, *next;
struct json_object *val;
if (key)
*key = NULL;
- if (op && op->type == T_DOT) {
+ if (type == T_DOT) {
if (key)
- *key = off2 ? json_object_get(uc_get_op(state, off2)->val) : NULL;
+ *key = off2 ? json_object_get(OP_VAL(off2)) : NULL;
return uc_execute_op_sequence(state, off1);
}
- else if (op && op->type == T_LBRACK && op->is_postfix) {
+ else if (type == T_LBRACK && OP_IS_POSTFIX(off)) {
if (key) {
val = off2 ? uc_execute_op_sequence(state, off2) : NULL;
@@ -233,20 +233,20 @@ uc_getref(struct uc_state *state, uint32_t off, struct json_object **key)
return uc_execute_op_sequence(state, off1);
}
- else if (op && op->type == T_LABEL) {
+ else if (type == T_LABEL) {
sc = state->scope;
while (true) {
- if (json_object_object_get_ex(sc->scope, json_object_get_string(op->val), NULL))
+ if (json_object_object_get_ex(sc->scope, json_object_get_string(OP_VAL(off)), NULL))
break;
next = uc_parent_scope(sc);
if (!next) {
if (state->strict_declarations) {
- return uc_new_exception(state, op->off,
+ return uc_new_exception(state, OP_POS(off),
"Reference error: access to undeclared variable %s",
- json_object_get_string(op->val));
+ json_object_get_string(OP_VAL(off)));
}
break;
@@ -256,7 +256,7 @@ uc_getref(struct uc_state *state, uint32_t off, struct json_object **key)
}
if (key)
- *key = json_object_get(op->val);
+ *key = json_object_get(OP_VAL(off));
return json_object_get(sc->scope);
}
@@ -271,7 +271,7 @@ uc_getref(struct uc_state *state, uint32_t off, struct json_object **key)
static struct json_object *
uc_getref_required(struct uc_state *state, uint32_t off, struct json_object **key)
{
- struct uc_op *op1 = uc_get_child(state, off, 0);
+ uint32_t child_off = OPn(off, 0);
struct json_object *scope, *skey, *rv;
char *lhs;
@@ -280,15 +280,17 @@ uc_getref_required(struct uc_state *state, uint32_t off, struct json_object **ke
if (!json_object_is_type(scope, json_type_array) &&
!json_object_is_type(scope, json_type_object)) {
if (!uc_is_type(scope, T_EXCEPTION)) {
- lhs = op1 ? uc_ref_to_str(state, uc_get_off(state, op1)) : NULL;
+ lhs = child_off ? uc_ref_to_str(state, child_off) : NULL;
if (lhs) {
- rv = uc_new_exception(state, op1->off, "Type error: `%s` is %s",
+ rv = uc_new_exception(state, OPn_POS(off, 0),
+ "Type error: `%s` is %s",
lhs, scope ? "not an array or object" : "null");
free(lhs);
}
else {
- rv = uc_new_exception(state, op1->off, "Type error: left-hand side is not an array or object");
+ rv = uc_new_exception(state, OPn_POS(off, 0),
+ "Type error: left-hand side is not an array or object");
}
json_object_put(scope);
@@ -310,12 +312,12 @@ uc_getref_required(struct uc_state *state, uint32_t off, struct json_object **ke
static struct json_object *
uc_getproto(struct json_object *obj)
{
- struct uc_op *op = json_object_get_userdata(obj);
+ struct uc_op *tag = json_object_get_userdata(obj);
- if (!op || (op->type != T_LBRACE && op->type <= __T_MAX) || !op->val)
+ if (!tag || (tag->type != T_LBRACE && tag->type <= __T_MAX) || !tag->val)
return NULL;
- return op->tag.proto;
+ return tag->tag.proto;
}
static struct json_object *
@@ -390,17 +392,16 @@ uc_setval(struct json_object *scope, struct json_object *key, struct json_object
static struct json_object *
uc_execute_assign(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- uint32_t label = op ? op->tree.operand[0] : 0;
- uint32_t value = op ? op->tree.operand[1] : 0;
+ uint32_t label_off = OPn(off, 0);
+ uint32_t value_off = OPn(off, 1);
struct json_object *scope, *key, *val;
- scope = uc_getref_required(state, label, &key);
+ scope = uc_getref_required(state, label_off, &key);
if (!key)
return scope;
- val = uc_execute_op_sequence(state, value);
+ val = uc_execute_op_sequence(state, value_off);
if (!uc_is_type(val, T_EXCEPTION))
uc_setval(scope, key, val);
@@ -414,18 +415,14 @@ uc_execute_assign(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_local(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off), *asop, *alop;
- uint32_t as = op ? op->tree.operand[0] : 0;
struct json_object *val, *rv = NULL;
+ uint32_t assign_off, label_off;
- while (as) {
- asop = uc_get_op(state, as);
- as = asop ? asop->tree.next : 0;
-
- switch (asop ? asop->type : 0) {
+ for (assign_off = OPn(off, 0); assign_off != 0; assign_off = OP_NEXT(assign_off)) {
+ switch (OP_TYPE(assign_off)) {
case T_ASSIGN:
- alop = uc_get_op(state, asop->tree.operand[0]);
- val = uc_execute_op_sequence(state, asop->tree.operand[1]);
+ label_off = OPn(assign_off, 0);
+ val = uc_execute_op_sequence(state, OPn(assign_off, 1));
if (uc_is_type(val, T_EXCEPTION))
return val;
@@ -433,7 +430,7 @@ uc_execute_local(struct uc_state *state, uint32_t off)
break;
case T_LABEL:
- alop = asop;
+ label_off = assign_off;
val = NULL;
break;
@@ -441,9 +438,9 @@ uc_execute_local(struct uc_state *state, uint32_t off)
continue;
}
- if (alop) {
+ if (label_off) {
json_object_put(rv);
- rv = uc_setval(state->scope->scope, alop->val, val);
+ rv = uc_setval(state->scope->scope, OP_VAL(label_off), val);
}
}
@@ -467,18 +464,17 @@ uc_test_condition(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_if(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- uint32_t cond = op ? op->tree.operand[0] : 0;
- uint32_t Then = op ? op->tree.operand[1] : 0;
- uint32_t Else = op ? op->tree.operand[2] : 0;
- bool res = uc_test_condition(state, cond);
+ uint32_t cond_off = OPn(off, 0);
+ uint32_t then_off = OPn(off, 1);
+ uint32_t else_off = OPn(off, 2);
+ bool res = uc_test_condition(state, cond_off);
if (state->exception)
return json_object_get(state->exception);
else if (res)
- return uc_execute_op_sequence(state, Then);
- else if (Else)
- return uc_execute_op_sequence(state, Else);
+ return uc_execute_op_sequence(state, then_off);
+ else if (else_off)
+ return uc_execute_op_sequence(state, else_off);
return NULL;
}
@@ -487,39 +483,40 @@ static struct json_object *
uc_execute_for(struct uc_state *state, uint32_t off)
{
struct json_object *kscope, *vscope, *val, *item, *ik, *iv = NULL, *rv = NULL;
- struct uc_op *loop = uc_get_op(state, off);
- struct uc_op *init = uc_get_child(state, off, 0);
- uint32_t test = loop ? loop->tree.operand[1] : 0;
- uint32_t incr = loop ? loop->tree.operand[2] : 0;
- uint32_t body = loop ? loop->tree.operand[3] : 0;
- struct uc_op *ikvar, *ivvar, *tag;
+ uint32_t init_off = OPn(off, 0);
+ uint32_t cond_off = OPn(off, 1);
+ uint32_t step_off = OPn(off, 2);
+ uint32_t body_off = OPn(off, 3);
+ uint32_t ik_off, iv_off;
size_t arridx, arrlen;
bool local = false;
+ struct uc_op *tag;
/* for (x in ...) loop variant */
- if (loop->is_for_in) {
- if (init->type == T_LOCAL) {
+ if (OP_IS_FOR_IN(off)) {
+ if (OP_TYPE(init_off) == T_LOCAL) {
local = true;
- init = uc_get_op(state, init->tree.operand[0]);
+ init_off = OPn(init_off, 0);
}
- ikvar = uc_get_op(state, init->tree.operand[0]);
- ik = ikvar->val;
- kscope = local ? state->scope->scope : uc_getref(state, uc_get_off(state, ikvar), NULL);
+ ik_off = OPn(init_off, 0);
+ ik = OP_VAL(ik_off);
+ kscope = local ? state->scope->scope : uc_getref(state, ik_off, NULL);
if (uc_is_type(kscope, T_EXCEPTION))
return kscope;
- if (ikvar->tree.next) {
- ivvar = uc_get_op(state, ikvar->tree.next);
- iv = ivvar->val;
- vscope = local ? kscope : uc_getref(state, uc_get_off(state, ivvar), NULL);
+ iv_off = OP_NEXT(ik_off);
+
+ if (iv_off) {
+ iv = OP_VAL(iv_off);
+ vscope = local ? kscope : uc_getref(state, iv_off, NULL);
if (uc_is_type(vscope, T_EXCEPTION))
return vscope;
}
- val = uc_execute_op_sequence(state, init->tree.operand[1]);
+ val = uc_execute_op_sequence(state, OPn(init_off, 1));
if (uc_is_type(val, T_EXCEPTION))
return val;
@@ -539,7 +536,7 @@ uc_execute_for(struct uc_state *state, uint32_t off)
json_object_put(rv);
- rv = uc_execute_op_sequence(state, body);
+ rv = uc_execute_op_sequence(state, body_off);
tag = json_object_get_userdata(rv);
switch (tag ? tag->type : 0) {
@@ -566,7 +563,7 @@ uc_execute_for(struct uc_state *state, uint32_t off)
json_object_put(rv);
- rv = uc_execute_op_sequence(state, body);
+ rv = uc_execute_op_sequence(state, body_off);
tag = json_object_get_userdata(rv);
switch (tag ? tag->type : 0) {
@@ -591,8 +588,8 @@ uc_execute_for(struct uc_state *state, uint32_t off)
return NULL;
}
- if (init) {
- val = uc_execute_op_sequence(state, uc_get_off(state, init));
+ if (init_off) {
+ val = uc_execute_op_sequence(state, init_off);
if (uc_is_type(val, T_EXCEPTION))
return val;
@@ -600,10 +597,10 @@ uc_execute_for(struct uc_state *state, uint32_t off)
json_object_put(val);
}
- while (test ? uc_test_condition(state, test) : true) {
+ while (cond_off ? uc_test_condition(state, cond_off) : true) {
json_object_put(rv);
- rv = uc_execute_op_sequence(state, body);
+ rv = uc_execute_op_sequence(state, body_off);
tag = json_object_get_userdata(rv);
switch (tag ? tag->type : 0) {
@@ -617,8 +614,8 @@ uc_execute_for(struct uc_state *state, uint32_t off)
return NULL;
}
- if (incr) {
- val = uc_execute_op_sequence(state, incr);
+ if (step_off) {
+ val = uc_execute_op_sequence(state, step_off);
if (uc_is_type(val, T_EXCEPTION)) {
json_object_put(rv);
@@ -638,9 +635,8 @@ uc_execute_for(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_while(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- uint32_t test = op ? op->tree.operand[0] : 0;
- uint32_t body = op ? op->tree.operand[1] : 0;
+ uint32_t test = OPn(off, 0);
+ uint32_t body = OPn(off, 1);
struct json_object *v, *rv = NULL;
struct uc_op *tag = NULL;
bool cond;
@@ -682,19 +678,20 @@ uc_execute_while(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_and_or(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
+ bool is_or = (OP_TYPE(off) == T_OR);
struct json_object *val = NULL;
- int i;
+ uint32_t op_off;
+ int i = 0;
- for (i = 0; i < ARRAY_SIZE(op->tree.operand) && op->tree.operand[i]; i++) {
+ for (op_off = OPn(off, 0); op_off != 0 && i < OPn_NUM; op_off = OPn(off, ++i)) {
json_object_put(val);
- val = uc_execute_op_sequence(state, op->tree.operand[i]);
+ val = uc_execute_op_sequence(state, op_off);
if (uc_is_type(val, T_EXCEPTION))
break;
- if (uc_val_is_truish(val) == (op->type == T_OR))
+ if (uc_val_is_truish(val) == is_or)
break;
}
@@ -763,19 +760,19 @@ uc_cmp(int how, struct json_object *v1, struct json_object *v2)
}
static struct json_object *
-_uc_get_operands(struct uc_state *state, struct uc_op *op, size_t n, struct json_object **v)
+_uc_get_operands(struct uc_state *state, uint32_t op_off, size_t n, struct json_object **v)
{
struct json_object *ctx = NULL;
- struct uc_op *child;
+ uint32_t child_off;
size_t i, j;
for (i = 0; i < n; i++) {
- child = op ? uc_get_op(state, op->tree.operand[i]) : NULL;
+ child_off = OPn(op_off, i);
- if (child && child->is_list)
- v[i] = uc_execute_list(state, uc_get_off(state, child));
- else if (child)
- v[i] = uc_execute_op_sequence(state, uc_get_off(state, child));
+ if (child_off && OP_IS_LIST(child_off))
+ v[i] = uc_execute_list(state, child_off);
+ else if (child_off)
+ v[i] = uc_execute_op_sequence(state, child_off);
else
v[i] = NULL;
@@ -798,21 +795,20 @@ _uc_get_operands(struct uc_state *state, struct uc_op *op, size_t n, struct json
return NULL;
}
-#define uc_get_operands(state, op, vals) \
+#define uc_get_operands(state, off, vals) \
do { \
- struct json_object *ex = _uc_get_operands(state, op, ARRAY_SIZE(vals), vals); \
+ struct json_object *ex = _uc_get_operands(state, off, ARRAY_SIZE(vals), vals); \
if (ex) return ex; \
} while(0)
static struct json_object *
uc_execute_rel(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *v[2], *rv;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
- rv = xjs_new_boolean(uc_cmp(op->type, v[0], v[1]));
+ rv = xjs_new_boolean(uc_cmp(OP_TYPE(off), v[0], v[1]));
json_object_put(v[0]);
json_object_put(v[1]);
@@ -864,14 +860,13 @@ uc_eq(struct json_object *v1, struct json_object *v2)
static struct json_object *
uc_execute_equality(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *v[2], *rv;
bool equal = false;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
equal = uc_eq(v[0], v[1]);
- rv = xjs_new_boolean((op->type == T_EQS) ? equal : !equal);
+ rv = xjs_new_boolean((OP_TYPE(off) == T_EQS) ? equal : !equal);
json_object_put(v[0]);
json_object_put(v[1]);
@@ -882,13 +877,12 @@ uc_execute_equality(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_in(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *v[2], *item;
size_t arrlen, arridx;
bool found = false;
const char *key;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
if (json_object_is_type(v[1], json_type_array)) {
for (arridx = 0, arrlen = json_object_array_length(v[1]);
@@ -915,13 +909,12 @@ uc_execute_in(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_inc_dec(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
+ bool is_inc = (OP_TYPE(off) == T_INC);
struct json_object *val, *nval, *scope, *key;
- uint32_t label = op ? op->tree.operand[0] : 0;
int64_t n;
double d;
- scope = uc_getref_required(state, label, &key);
+ scope = uc_getref_required(state, OPn(off, 0), &key);
if (!key)
return scope;
@@ -932,14 +925,14 @@ uc_execute_inc_dec(struct uc_state *state, uint32_t off)
json_object_put(key);
if (uc_cast_number(val, &n, &d) == json_type_double)
- nval = uc_new_double(d + (op->type == T_INC ? 1.0 : -1.0));
+ nval = uc_new_double(d + (is_inc ? 1.0 : -1.0));
else
- nval = xjs_new_int64(n + (op->type == T_INC ? 1 : -1));
+ nval = xjs_new_int64(n + (is_inc ? 1 : -1));
json_object_put(uc_setval(scope, key, nval));
/* postfix inc/dec, return old val */
- if (op->is_postfix)
+ if (OP_IS_POSTFIX(off))
return val;
json_object_put(val);
@@ -950,12 +943,11 @@ uc_execute_inc_dec(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_list(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *ex, *val, *arr = xjs_new_array();
size_t i;
- while (op) {
- val = uc_execute_op(state, uc_get_off(state, op));
+ while (off) {
+ val = uc_execute_op(state, off);
if (uc_is_type(val, T_EXCEPTION)) {
json_object_put(arr);
@@ -963,9 +955,10 @@ uc_execute_list(struct uc_state *state, uint32_t off)
return val;
}
- if (op->is_ellip) {
+ if (OP_IS_ELLIP(off)) {
if (!json_object_is_type(val, json_type_array)) {
- ex = uc_new_exception(state, op->off, "Type error: (%s) is not iterable",
+ ex = uc_new_exception(state, OP_POS(off),
+ "Type error: (%s) is not iterable",
json_object_get_string(val));
json_object_put(arr);
@@ -983,7 +976,7 @@ uc_execute_list(struct uc_state *state, uint32_t off)
json_object_array_add(arr, val);
}
- op = uc_get_op(state, op->tree.next);
+ off = OP_NEXT(off);
}
return arr;
@@ -993,12 +986,12 @@ static struct json_object *
uc_execute_object(struct uc_state *state, uint32_t off)
{
struct json_object *ex, *v, *obj = uc_new_object(NULL);
- struct uc_op *key;
+ uint32_t key_off;
char *istr;
size_t i;
- for (key = uc_get_child(state, off, 0); key; key = uc_get_op(state, key->tree.next)) {
- v = uc_execute_op_sequence(state, key->tree.operand[0]);
+ for (key_off = OPn(off, 0); key_off != 0; key_off = OP_NEXT(key_off)) {
+ v = uc_execute_op_sequence(state, OPn(key_off, 0));
if (uc_is_type(v, T_EXCEPTION)) {
json_object_put(obj);
@@ -1006,7 +999,7 @@ uc_execute_object(struct uc_state *state, uint32_t off)
return v;
}
- if (key->type == T_ELLIP) {
+ if (OP_TYPE(key_off) == T_ELLIP) {
switch (json_object_get_type(v)) {
case json_type_object:
; /* a label can only be part of a statement and a declaration is not a statement */
@@ -1029,7 +1022,8 @@ uc_execute_object(struct uc_state *state, uint32_t off)
break;
default:
- ex = uc_new_exception(state, key->off, "Type error: (%s) is not iterable",
+ ex = uc_new_exception(state, OP_POS(key_off),
+ "Type error: (%s) is not iterable",
json_object_get_string(v));
json_object_put(obj);
@@ -1039,7 +1033,7 @@ uc_execute_object(struct uc_state *state, uint32_t off)
}
}
else {
- json_object_object_add(obj, json_object_get_string(key->val), v);
+ json_object_object_add(obj, json_object_get_string(OP_VAL(key_off)), v);
}
}
@@ -1050,7 +1044,7 @@ struct json_object *
uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this,
struct json_object *func, struct json_object *argvals)
{
- struct uc_op *op, *tag = json_object_get_userdata(func);
+ struct uc_op *tag = json_object_get_userdata(func);
struct json_object *arr, *rv = NULL;
struct uc_callstack callstack = {};
struct uc_function *fn, *prev_fn;
@@ -1062,14 +1056,12 @@ uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this,
if (!tag)
return NULL;
- op = uc_get_op(state, off);
-
if (state->calldepth >= 1000)
- return uc_new_exception(state, op->off, "Runtime error: Too much recursion");
+ return uc_new_exception(state, OP_POS(off), "Runtime error: Too much recursion");
callstack.next = state->callstack;
callstack.function = state->function;
- callstack.off = op ? op->off : 0;
+ callstack.off = OP_POS(off);
if (tag->is_arrow)
callstack.ctx = state->callstack ? json_object_get(state->callstack->ctx) : NULL;
@@ -1128,7 +1120,7 @@ uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this,
case T_BREAK:
case T_CONTINUE:
json_object_put(rv);
- rv = uc_new_exception(state, uc_get_off(state, tag),
+ rv = uc_new_exception(state, tag->off,
"Syntax error: %s statement must be inside loop",
uc_get_tokenname(tag->type));
break;
@@ -1160,19 +1152,19 @@ uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this,
static struct json_object *
uc_execute_call(struct uc_state *state, uint32_t off)
{
- struct uc_op *decl, *op = uc_get_op(state, off);
- struct uc_op *op1 = uc_get_child(state, off, 0);
struct json_object *v[2], *rv;
+ struct uc_op *decl;
char *lhs;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
decl = json_object_get_userdata(v[0]);
if (!decl || (decl->type != T_FUNC && decl->type != T_CFUNC)) {
- lhs = uc_ref_to_str(state, uc_get_off(state, op1));
+ lhs = uc_ref_to_str(state, OPn(off, 0));
- rv = uc_new_exception(state, op1->off, "Type error: %s is not a function",
+ rv = uc_new_exception(state, OPn_POS(off, 0),
+ "Type error: %s is not a function",
lhs ? lhs : "left-hand side expression");
free(lhs);
@@ -1224,8 +1216,7 @@ uc_write_str(struct json_object *v)
static struct json_object *
uc_execute_exp(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- struct json_object *val = uc_execute_op_sequence(state, op ? op->tree.operand[0] : 0);
+ struct json_object *val = uc_execute_op_sequence(state, OPn(off, 0));
struct uc_op *tag = val ? json_object_get_userdata(val) : NULL;
switch (tag ? tag->type : 0) {
@@ -1246,14 +1237,13 @@ uc_execute_exp(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_unary_plus_minus(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- struct uc_op *op1 = uc_get_child(state, off, 0);
+ bool is_sub = (OP_TYPE(off) == T_SUB);
struct json_object *v[1];
enum json_type t;
int64_t n;
double d;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
t = uc_cast_number(v[0], &n, &d);
@@ -1261,20 +1251,20 @@ uc_execute_unary_plus_minus(struct uc_state *state, uint32_t off)
switch (t) {
case json_type_int:
- if (op1->is_overflow)
- return xjs_new_int64(((n >= 0) == (op->type == T_SUB)) ? INT64_MIN : INT64_MAX);
+ if (OPn_IS_OVERFLOW(off, 0))
+ return xjs_new_int64(((n >= 0) == is_sub) ? INT64_MIN : INT64_MAX);
- return xjs_new_int64((op->type == T_SUB) ? -n : n);
+ return xjs_new_int64(is_sub ? -n : n);
default:
- return uc_new_double((op->type == T_SUB) ? -d : d);
+ return uc_new_double(is_sub ? -d : d);
}
}
static struct json_object *
uc_execute_arith(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
+ int type = OP_TYPE(off);
struct json_object *v[2], *rv;
enum json_type t1, t2;
const char *s1, *s2;
@@ -1283,12 +1273,12 @@ uc_execute_arith(struct uc_state *state, uint32_t off)
double d1, d2;
char *s;
- if (!op->tree.operand[1])
+ if (!OPn(off, 1))
return uc_execute_unary_plus_minus(state, off);
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
- if (op->type == T_ADD &&
+ if (type == T_ADD &&
(json_object_is_type(v[0], json_type_string) ||
json_object_is_type(v[1], json_type_string))) {
s1 = v[0] ? json_object_get_string(v[0]) : "null";
@@ -1318,7 +1308,7 @@ uc_execute_arith(struct uc_state *state, uint32_t off)
d1 = (t1 == json_type_double) ? d1 : (double)n1;
d2 = (t2 == json_type_double) ? d2 : (double)n2;
- switch (op->type) {
+ switch (type) {
case T_ADD:
return uc_new_double(d1 + d2);
@@ -1343,7 +1333,7 @@ uc_execute_arith(struct uc_state *state, uint32_t off)
}
}
- switch (op->type) {
+ switch (type) {
case T_ADD:
return xjs_new_int64(n1 + n2);
@@ -1369,12 +1359,11 @@ uc_execute_arith(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_bitop(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *v[2];
int64_t n1, n2;
double d;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
if (uc_cast_number(v[0], &n1, &d) == json_type_double)
n1 = isnan(d) ? 0 : (int64_t)d;
@@ -1385,7 +1374,7 @@ uc_execute_bitop(struct uc_state *state, uint32_t off)
json_object_put(v[0]);
json_object_put(v[1]);
- switch (op->type) {
+ switch (OP_TYPE(off)) {
case T_LSHIFT:
return xjs_new_int64(n1 << n2);
@@ -1409,20 +1398,17 @@ uc_execute_bitop(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_not(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
-
- return xjs_new_boolean(!uc_test_condition(state, op ? op->tree.operand[0] : 0));
+ return xjs_new_boolean(!uc_test_condition(state, OPn(off, 0)));
}
static struct json_object *
uc_execute_compl(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *v[1];
int64_t n;
double d;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
if (uc_cast_number(v[0], &n, &d) == json_type_double)
n = isnan(d) ? 0 : (int64_t)d;
@@ -1432,20 +1418,29 @@ uc_execute_compl(struct uc_state *state, uint32_t off)
return xjs_new_int64(~n);
}
+static void
+uc_free_tag(struct json_object *v, void *ud)
+{
+ free(ud);
+}
+
static struct json_object *
uc_execute_return(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
+ struct uc_op *cpy = xalloc(sizeof(*cpy));
struct json_object *v[1], *rv;
- uc_get_operands(state, op, v);
+ memcpy(cpy, OP(off), sizeof(*cpy));
+ cpy->off = off;
+
+ uc_get_operands(state, off, v);
json_object_put(state->rval);
state->rval = v[0];
rv = xjs_new_boolean(false);
- json_object_set_userdata(rv, op, NULL);
+ json_object_set_userdata(rv, cpy, uc_free_tag);
return rv;
}
@@ -1453,10 +1448,13 @@ uc_execute_return(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_break_cont(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
+ struct uc_op *cpy = xalloc(sizeof(*cpy));
struct json_object *rv = xjs_new_int64(0);
- json_object_set_userdata(rv, op, NULL);
+ memcpy(cpy, OP(off), sizeof(*cpy));
+ cpy->off = off;
+
+ json_object_set_userdata(rv, cpy, uc_free_tag);
return rv;
}
@@ -1464,12 +1462,11 @@ uc_execute_break_cont(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_function(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
- struct uc_op *op1 = uc_get_child(state, off, 0);
- struct json_object *obj = uc_new_func(state, op, state->scope);
+ struct json_object *obj = uc_new_func(state, off, state->scope);
+ struct json_object *val = OPn_VAL(off, 0);
- if (op1)
- uc_setval(state->scope->scope, op1->val, obj);
+ if (val)
+ uc_setval(state->scope->scope, val, obj);
return obj;
}
@@ -1483,19 +1480,21 @@ uc_execute_this(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_try_catch(struct uc_state *state, uint32_t off)
{
- struct uc_op *tag, *op = uc_get_op(state, off);
- struct json_object *rv;
+ struct json_object *evar, *rv;
+ struct uc_op *tag;
- rv = uc_execute_op_sequence(state, op->tree.operand[0]);
+ rv = uc_execute_op_sequence(state, OPn(off, 0));
if (uc_is_type(rv, T_EXCEPTION)) {
- if (op->tree.operand[1]) {
+ evar = OPn_VAL(off, 1);
+
+ if (evar) {
/* remove the T_EXCEPTION type from the object to avoid handling
* it as a new exception in the catch block */
tag = json_object_get_userdata(rv);
tag->type = T_LBRACE;
- json_object_put(uc_setval(state->scope->scope, uc_get_child(state, off, 1)->val,
+ json_object_put(uc_setval(state->scope->scope, evar,
json_object_get(rv)));
}
@@ -1503,16 +1502,16 @@ uc_execute_try_catch(struct uc_state *state, uint32_t off)
state->exception = NULL;
json_object_put(rv);
- rv = uc_execute_op_sequence(state, op->tree.operand[2]);
+ rv = uc_execute_op_sequence(state, OPn(off, 2));
}
return rv;
}
static bool
-uc_match_case(struct uc_state *state, struct json_object *v, struct uc_op *Case)
+uc_match_case(struct uc_state *state, struct json_object *v, uint32_t case_off)
{
- struct json_object *caseval = uc_execute_op_sequence(state, Case->tree.operand[0]);
+ struct json_object *caseval = uc_execute_op_sequence(state, OPn(case_off, 0));
bool rv = uc_eq(v, caseval);
json_object_put(caseval);
@@ -1522,48 +1521,41 @@ uc_match_case(struct uc_state *state, struct json_object *v, struct uc_op *Case)
static struct json_object *
uc_execute_switch_case(struct uc_state *state, uint32_t off)
{
- struct uc_op *Default = NULL, *Case = NULL, *jmp = NULL;
- struct uc_op *op = uc_get_op(state, off);
+ uint32_t case_off, default_off = 0, jmp_off = 0;
struct json_object *v[1], *rv = NULL;
- uc_get_operands(state, op, v);
+ uc_get_operands(state, off, v);
/* First try to find matching case... */
- for (Case = uc_get_child(state, off, 1);
- Case != NULL;
- Case = uc_get_op(state, Case->tree.next))
- {
+ for (case_off = OPn(off, 1); case_off != 0; case_off = OP_NEXT(case_off)) {
/* remember default case and throw on dupes */
- if (Case->type == T_DEFAULT) {
- if (Default) {
+ if (OP_TYPE(case_off) == T_DEFAULT) {
+ if (default_off) {
json_object_put(v[0]);
- return uc_new_exception(state, Case->off,
+ return uc_new_exception(state, OP_POS(case_off),
"Syntax error: more than one switch default case");
}
- Default = Case;
+ default_off = case_off;
continue;
}
/* Found a matching case, remember jump offset */
- if (uc_match_case(state, v[0], Case)) {
- jmp = Case;
+ if (uc_match_case(state, v[0], case_off)) {
+ jmp_off = case_off;
break;
}
}
/* jump to matching case (or default) and continue until break */
- for (Case = jmp ? jmp : Default;
- Case != NULL;
- Case = uc_get_op(state, Case->tree.next))
- {
+ for (case_off = jmp_off ? jmp_off : default_off; case_off != 0; case_off = OP_NEXT(case_off)) {
json_object_put(rv);
- if (Case == Default)
- rv = uc_execute_op_sequence(state, Default->tree.operand[0]);
+ if (OP_TYPE(case_off) == T_DEFAULT)
+ rv = uc_execute_op_sequence(state, OPn(case_off, 0));
else
- rv = uc_execute_op_sequence(state, Case->tree.operand[1]);
+ rv = uc_execute_op_sequence(state, OPn(case_off, 1));
if (uc_is_type(rv, T_BREAK)) {
json_object_put(rv);
@@ -1583,13 +1575,13 @@ uc_execute_switch_case(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_atom(struct uc_state *state, uint32_t off)
{
- return json_object_get(uc_get_op(state, off)->val);
+ return json_object_get(OP_VAL(off));
}
static struct json_object *
uc_execute_text(struct uc_state *state, uint32_t off)
{
- printf("%s", json_object_get_string(uc_get_op(state, off)->val));
+ printf("%s", json_object_get_string(OP_VAL(off)));
return NULL;
}
@@ -1597,7 +1589,6 @@ uc_execute_text(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_label(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
struct json_object *scope, *key, *val;
scope = uc_getref(state, off, &key);
@@ -1606,9 +1597,9 @@ uc_execute_label(struct uc_state *state, uint32_t off)
state->ctx = NULL;
if (state->strict_declarations && scope == NULL) {
- return uc_new_exception(state, op->off,
+ return uc_new_exception(state, OP_POS(off),
"Reference error: %s is not defined",
- json_object_get_string(op->val));
+ json_object_get_string(OP_VAL(off)));
}
val = uc_getval(scope, key);
@@ -1641,21 +1632,17 @@ uc_execute_dot(struct uc_state *state, uint32_t off)
static struct json_object *
uc_execute_lbrack(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
-
/* postfix access */
- if (op->is_postfix)
+ if (OP_IS_POSTFIX(off))
return uc_execute_dot(state, off);
- return uc_execute_list(state, op->tree.operand[0]);
+ return uc_execute_list(state, OPn(off, 0));
}
static struct json_object *
uc_execute_exp_list(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
-
- return uc_execute_op_sequence(state, op->tree.operand[0]);
+ return uc_execute_op_sequence(state, OPn(off, 0));
}
static struct json_object *(*fns[__T_MAX])(struct uc_state *, uint32_t) = {
@@ -1718,12 +1705,13 @@ static struct json_object *(*fns[__T_MAX])(struct uc_state *, uint32_t) = {
static struct json_object *
uc_execute_op(struct uc_state *state, uint32_t off)
{
- struct uc_op *op = uc_get_op(state, off);
+ int type = OP_TYPE(off);
- if (!fns[op->type])
- return uc_new_exception(state, op->off, "Runtime error: Unrecognized opcode %d", op->type);
+ if (!fns[type])
+ return uc_new_exception(state, OP_POS(off),
+ "Runtime error: Unrecognized opcode %d", type);
- return fns[op->type](state, off);
+ return fns[type](state, off);
}
static struct json_object *
@@ -1731,7 +1719,6 @@ uc_execute_op_sequence(struct uc_state *state, uint32_t off)
{
struct json_object *v = NULL;
struct uc_op *tag = NULL;
- struct uc_op *op = NULL;
while (off) {
json_object_put(v);
@@ -1747,8 +1734,7 @@ uc_execute_op_sequence(struct uc_state *state, uint32_t off)
return v;
}
- op = uc_get_op(state, off);
- off = op ? op->tree.next : 0;
+ off = OP_NEXT(off);
}
return v;