DEFINEFN vinfo_t* PsycoNumber_Remainder(PsycoObject* po, vinfo_t* v, vinfo_t* w) { PyTypeObject* vtp = Psyco_NeedType(po, v); if (vtp == NULL) return NULL; if (vtp->tp_as_number == NULL) { /* <= 2.2 only: special-case strings */ if (PsycoString_Check(vtp)) return psyco_generic_call(po, PyString_Format, CfReturnRef|CfPyErrIfNull, "vv", v, w); #ifdef Py_USING_UNICODE else if (PsycoUnicode_Check(vtp)) return psyco_generic_call(po, # if PSYCO_CAN_CALL_UNICODE PyUnicode_Format, # else PyNumber_Remainder, # endif CfReturnRef|CfPyErrIfNull, "vv", v, w); #endif } return binary_op(po, v, w, NB_SLOT(nb_remainder), "%"); }
void Stokhos::PseudoSpectralOrthogPolyExpansion<ordinal_type, value_type, point_compare_type, node_type>:: divide(Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& a, const Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& b) { #ifdef STOKHOS_TEUCHOS_TIME_MONITOR TEUCHOS_FUNC_TIME_MONITOR("Stokhos::OrthogPolyExpansionBase::divide(OPA,OPA)"); #endif if (b.size() == 1) { ordinal_type pc = a.size(); if (c.size() != pc) c.resize(pc); const value_type* ca = a.coeff(); const value_type* cb = b.coeff(); value_type* cc = c.coeff(); for (ordinal_type i=0; i<pc; i++) cc[i] = ca[i]/cb[0]; } else { if (use_quad_for_division) binary_op(div_quad_func(), c, a, b); else OrthogPolyExpansionBase<ordinal_type, value_type, node_type>::divide(c, a, b); } }
void Stokhos::QuadOrthogPolyExpansion<ordinal_type, value_type>:: atan2(Stokhos::OrthogPolyApprox<ordinal_type, value_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type>& a, const value_type& b) { binary_op(atan2_quad_func(), c, a, b); }
void Stokhos::PseudoSpectralOrthogPolyExpansion<ordinal_type, value_type, point_compare_type, node_type>:: atan2(Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& a, const value_type& b) { binary_op(atan2_quad_func(), c, a, b); }
void Stokhos::QuadOrthogPolyExpansion<ordinal_type, value_type>:: timesEqual(Stokhos::OrthogPolyApprox<ordinal_type, value_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type>& x) { if (use_quad_for_times) { binary_op(times_quad_func(), c, c, x); return; } ordinal_type p = c.size(); ordinal_type xp = x.size(); ordinal_type pc; if (p > 1 && xp > 1) pc = sz; else pc = p*xp; TEST_FOR_EXCEPTION(sz < pc, std::logic_error, "Stokhos::QuadOrthogPolyExpansion::timesEqual()" << ": Expansion size (" << sz << ") is too small for computation."); if (c.size() != pc) c.resize(pc); value_type* cc = c.coeff(); const value_type* xc = x.coeff(); if (p > 1 && xp > 1) { // Copy c coefficients into temporary array value_type* tc = Stokhos::ds_array<value_type>::get_and_fill(cc,p); value_type tmp, cijk; ordinal_type i,j; for (ordinal_type k=0; k<pc; k++) { tmp = value_type(0.0); ordinal_type n = Cijk->num_values(k); for (ordinal_type l=0; l<n; l++) { Cijk->value(k,l,i,j,cijk); if (i < p && j < xp) tmp += cijk*tc[i]*xc[j]; } cc[k] = tmp / basis->norm_squared(k); } } else if (p > 1) { for (ordinal_type i=0; i<p; i++) cc[i] *= xc[0]; } else if (xp > 1) { for (ordinal_type i=1; i<xp; i++) cc[i] = cc[0]*xc[i]; cc[0] *= xc[0]; } else { cc[0] *= xc[0]; } }
virtual void execute( MemoryInterface *global ) { this->global = global; const int second = getNumberValue( ); const int first = getNumberValue( ); Object *result = new ArgumentType( binary_op(first,second) ); this->global->push( result ); }
void Stokhos::QuadOrthogPolyExpansion<ordinal_type, value_type>:: times(Stokhos::OrthogPolyApprox<ordinal_type, value_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type>& a, const Stokhos::OrthogPolyApprox<ordinal_type, value_type>& b) { if (use_quad_for_times) { binary_op(times_quad_func(), c, a, b); return; } ordinal_type pa = a.size(); ordinal_type pb = b.size(); ordinal_type pc; if (pa > 1 && pb > 1) pc = sz; else pc = pa*pb; TEST_FOR_EXCEPTION(sz < pc, std::logic_error, "Stokhos::QuadOrthogPolyExpansion::times()" << ": Expansion size (" << sz << ") is too small for computation."); if (c.size() != pc) c.resize(pc); const value_type* ca = a.coeff(); const value_type* cb = b.coeff(); value_type* cc = c.coeff(); if (pa > 1 && pb > 1) { value_type tmp, cijk; ordinal_type i,j; for (ordinal_type k=0; k<pc; k++) { tmp = value_type(0.0); ordinal_type n = Cijk->num_values(k); for (ordinal_type l=0; l<n; l++) { Cijk->value(k,l,i,j,cijk); if (i < pa && j < pb) tmp += cijk*ca[i]*cb[j]; } cc[k] = tmp / basis->norm_squared(k); } } else if (pa > 1) { for (ordinal_type i=0; i<pc; i++) cc[i] = ca[i]*cb[0]; } else if (pb > 1) { for (ordinal_type i=0; i<pc; i++) cc[i] = ca[0]*cb[i]; } else { cc[0] = ca[0]*cb[0]; } }
void Stokhos::PseudoSpectralOrthogPolyExpansion<ordinal_type, value_type, point_compare_type, node_type>:: divide(Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& c, const value_type& a, const Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& b) { if (use_quad_for_division) binary_op(div_quad_func(), c, a, b); else OrthogPolyExpansionBase<ordinal_type, value_type, node_type>::divide(c, a, b); }
void Stokhos::PseudoSpectralOrthogPolyExpansion<ordinal_type, value_type, point_compare_type, node_type>:: timesEqual( Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& x) { if (use_quad_for_times) binary_op(times_quad_func(), c, c, x); else OrthogPolyExpansionBase<ordinal_type, value_type, node_type>::timesEqual(c, x); }
void Stokhos::QuadOrthogPolyExpansion<ordinal_type, value_type>:: divideEqual(Stokhos::OrthogPolyApprox<ordinal_type, value_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type >& x) { if (x.size() == 1) { ordinal_type p = c.size(); value_type* cc = c.coeff(); const value_type* xc = x.coeff(); for (ordinal_type i=0; i<p; i++) cc[i] /= xc[0]; } else binary_op(div_quad_func(), c, c, x); }
inline SPROUT_CONSTEXPR T inner_product_ra( RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2, typename std::iterator_traits<RandomAccessIterator1>::difference_type pivot, T init ) { return pivot == 0 ? binary_op(init, binary_op2(*first1, *first2)) : sprout::detail::inner_product_ra( sprout::next(first1, pivot), last1, sprout::next(first2, pivot), binary_op1, binary_op2, (sprout::distance(first1, last1) - pivot) / 2, sprout::detail::inner_product_ra( first1, sprout::next(first1, pivot), first2, binary_op1, binary_op2, pivot / 2, init ) ) ; }
void Stokhos::QuadOrthogPolyExpansion<ordinal_type, value_type>:: divide(Stokhos::OrthogPolyApprox<ordinal_type, value_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type>& a, const Stokhos::OrthogPolyApprox<ordinal_type, value_type>& b) { if (b.size() == 1) { ordinal_type pc = a.size(); if (c.size() != pc) c.resize(pc); const value_type* ca = a.coeff(); const value_type* cb = b.coeff(); value_type* cc = c.coeff(); for (ordinal_type i=0; i<pc; i++) cc[i] = ca[i]/cb[0]; } else binary_op(div_quad_func(), c, a, b); }
static opexpr_code(stream, node, need_lval) { auto op = node[0]; /* Unary prefix operators */ if ( node[1] == 1 ) unary_pre( stream, node, need_lval ); /* Unary postfix operators (marked binary in the tree) */ else if ( op == '++' || op == '--' ) unary_post( stream, node, need_lval ); /* These operators are handled separately because of short-circuiting */ else if ( op == '&&' || op == '||' ) logical_bin( stream, node ); /* And these are because they don't evaluate their second argument */ else if ( op == '->' || op == '.' ) member_bin( stream, node, need_lval ); else if ( op == '<' || op == '>' || op == '<=' || op == '>=' || op == '==' || op == '!=' ) cmp_op( stream, node ); else if ( op == ',' ) { expr_code( stream, node[3], 0 ); expr_code( stream, node[4], 0 ); } /* Binary operators */ else if ( node[1] == 2 ) binary_op( stream, node, need_lval ); /* The ternary operator also short-circuits */ else if ( op == '?:' ) conditional( stream, node ); else int_error( "Unknown operator: '%Mc'", node[0] ); }
void Stokhos::PseudoSpectralOrthogPolyExpansion<ordinal_type, value_type, point_compare_type, node_type>:: divideEqual( Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& c, const Stokhos::OrthogPolyApprox<ordinal_type, value_type, node_type>& x) { #ifdef STOKHOS_TEUCHOS_TIME_MONITOR TEUCHOS_FUNC_TIME_MONITOR("Stokhos::OrthogPolyExpansionBase::divideEqual(OPA)"); #endif if (x.size() == 1) { ordinal_type p = c.size(); value_type* cc = c.coeff(); const value_type* xc = x.coeff(); for (ordinal_type i=0; i<p; i++) cc[i] /= xc[0]; } else { if (use_quad_for_division) binary_op(div_quad_func(), c, c, x); else OrthogPolyExpansionBase<ordinal_type, value_type, node_type>::divideEqual(c, x); } }
// take a tokenized expression (expr) with precalculated internal values (llp and ldp) and evaluate it // HIHI maybe put the return value in an arg, and pass back an error flag? -- otherwise need *inf, so I can show_errors? // -- move this back into cpp?? It's not generic enough. int32_t calculate_expr(uint8_t *expr, uint64_t *llp, int32_t llcnt, double *ldp, int32_t ldblcnt) { uint8_t *s, *e, *p, *c, restart, tok, type[200]; int i; restart = 0; i = 200; while (--i >= 0) type[i] = 0; // init the unused part of the array to 0 i = llcnt; while (--i >= 0) type[i] = 1; // init all the ints to uint64_t i = ldblcnt; while (--i >= 0) type[199 - i] = 42; // init all the floats to long double // HIHI! enforce that llcnt + ldblcnt < 256 - TOK_SIZEOF s = expr; // scan to the first ')' token, scan backwards to the first '(' token -- then evaluate that subexpression // -- each pair of parens get deleted after their whole subexpression is done parsing while (*s != TOK_C_PAREN && *s != TOK_ILLEGAL) ++s; while (*s != TOK_ILLEGAL) { e = s; while (*--s != TOK_O_PAREN); // find the highest precedence operator in the expression // no "primary" operators are allowed in the preprocessor -- scan right to left for the first active unary operator p = e; // + - ! ~ sizeof(cast) (casts)=masking while (*--p != TOK_O_PAREN && restart == 0) { if (*p == TOK_B_NOT || *p == TOK_NOT) // in this compiler, bitwise not and boolean not are the same operator { tok = next_tok(p); // the next token *must* be an rvalue for the operator // if (tok <= TOK_SIZEOF, or if the variable is a float?) show_error; // modify the rvalue at the right end of the expression llp[tok - TOK_SIZEOF - 1] = ~llp[tok - TOK_SIZEOF - 1]; *p = TOK_NO_OP; // now that the operator has been processed, delete it p = e; } // a minus sign is a NEG unary operator if there is another operator (and not a "variable") to the left // HIHI!! gotta handle the float case, too! else if (*p == TOK_SUB && prev_tok(p) <= TOK_SIZEOF) { tok = next_tok(p); // the next token *must* be an rvalue for the operator // if (tok <= TOK_SIZEOF) show_error; // modify the rvalue at the right end of the expression // check "type" to see if this tok is a float llp[tok - TOK_SIZEOF - 1] = - (int64_t) llp[tok - TOK_SIZEOF - 1]; *p = TOK_NO_OP; // now that the operator has been processed, delete it p = e; } // a plus sign is a unary operator (and a no-op) if there is another operator (and not a "variable") to the left else if (*p == TOK_ADD && prev_tok(p) <= TOK_SIZEOF) { *p = TOK_NO_OP; // delete the + operator and restart the scan p = e; } else if (*p >= TOK_BOOL_T && *p <= TOK_UNSGN_T) { // either this is an input into sizeof (as a cast), or it's a cast of the following value // -- so (multiple) type keywords should be the only thing inside the parens // -- because the preprocessor doesn't know about function or variable declarations c = p - 1; while (*c == TOK_NO_OP || (*c >= TOK_BOOL_T && *c <= TOK_UNSGN_T)) --c; // verify the open and close parens around this (cast) // obviously, s also points at the '(' and e points at the ')' // HIHI!!! woops! the next tok may be a *, and not a paren! Need to scan that direction, too! if (next_tok(p) != TOK_C_PAREN || c != s) { i = 0; // show_error(0,"typecast(?) not in parens",NULL,1); } p = s; while (*--p == TOK_NO_OP); if (*p == TOK_SIZEOF) // immediately convert a sizeof(cast) into a variable (with the correct value) { // get the next open int variable number type[llcnt] = 0; i = -1; while (type[++i] != 0); if (i == llcnt) ++llcnt; // HIHI!! need to put a 199 limit on llcnt! // replace the sizeof() token with the actual size, and no-op the cast *p = i + TOK_SIZEOF + 1; llp[i] = size_of(s + 1); type[i] = 1; while (*++p != TOK_C_PAREN) *p = TOK_NO_OP; *p = TOK_NO_OP; restart = 1; } else { // do an immediate mask and type modification of the rvalue variable tok = next_tok(p); // get the variable index i = size_of(s + 1) - 1; // get the byte count - 1 if (i == 3) i = 2; // convert to a mask index if (i < 3) llp[tok - TOK_SIZEOF - 1] &= size_mask[i]; else i = 3; type[tok - TOK_SIZEOF - 1] = 4 - i; // convert to a type (maybe I should reverse the order of the types?? HIHI) } } } // then the multiplicative operators -- p already points to the start while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_MULT || *p == TOK_DIV || *p == TOK_MOD) { restart = 1; binary_op(p, llp, type); } } // then additiive p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_ADD || *p == TOK_SUB) { restart = 1; binary_op(p, llp, type); } } // then shifts p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_SHR || *p == TOK_SHL) { restart = 1; binary_op(p, llp, type); } } // then relational conditionals p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_LT || *p == TOK_B_GT || *p == TOK_B_LE || *p == TOK_B_GE) { restart = 1; binary_op(p, llp, type); } } // then equality conditionals p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_EQ || *p == TOK_B_NE) { restart = 1; binary_op(p, llp, type); } } // then bitwise operators -- AND & p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_AND) { restart = 1; binary_op(p, llp, type); } } // XOR ^ p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_XOR) { restart = 1; binary_op(p, llp, type); } } // OR | p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_OR) { restart = 1; binary_op(p, llp, type); } } // then booleans && p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_AND) { restart = 1; binary_op(p, llp, type); } } // || p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_OR) { restart = 1; binary_op(p, llp, type); } } // and last, the stupid "ternary condtional" ? evaluate right to left, p is already set properly while (restart == 0 && *--p != TOK_O_PAREN) { if (*p == TOK_QMARK) i = 8; // HIHI!!! gotta parse it and eliminate it from the expr } // are there any operators left between s and e? If not, destroy the parens of this fully evaluated subexpression. p = s + 1; while (*p > TOK_SIZEOF || *p == TOK_NO_OP) ++p; if (*p == TOK_C_PAREN) { *s = TOK_NO_OP; *p = TOK_NO_OP; } restart = 0; s = expr; while (*s != TOK_C_PAREN && *s != TOK_ILLEGAL) ++s; } // there must be one variable left in the expression now -- that's the return value p = expr + 1; while (*p < TOK_SIZEOF) ++p; if (llp[*p - TOK_SIZEOF - 1] == 0) return 0; return -1; }
bool run(struct context *context, struct byte_array *program, struct map *env, bool in_context) { null_check(context); null_check(program); program = byte_array_copy(program); program->current = program->data; struct program_state *state = NULL; enum Opcode inst = VM_NIL; if (context->runtime) { if (in_context) { if (!state) state = (struct program_state*)stack_peek(context->program_stack, 0); env = state->named_variables; // use the caller's variable set in the new state } else state = program_state_new(context, env); } while (program->current < program->data + program->length) { inst = (enum Opcode)*program->current; bool really = inst & VM_RLY; inst &= ~VM_RLY; #ifdef DEBUG display_program_counter(context, program); #endif program->current++; // increment past the instruction int32_t pc_offset = 0; switch (inst) { case VM_COM: case VM_ITR: if (iterate(context, inst, state, program)) goto done; break; case VM_RET: if (ret(context, program)) goto done; break; case VM_TRO: if (tro(context)) goto done; break; case VM_TRY: if (vm_trycatch(context, program)) goto done; break; case VM_EQU: case VM_MUL: case VM_DIV: case VM_ADD: case VM_SUB: case VM_NEQ: case VM_GTN: case VM_LTN: case VM_GRQ: case VM_LEQ: case VM_BND: case VM_BOR: case VM_MOD: case VM_XOR: case VM_INV: case VM_RSF: case VM_LSF: binary_op(context, inst); break; case VM_ORR: case VM_AND: pc_offset = boolean_op(context, program, inst); break; case VM_NEG: case VM_NOT: unary_op(context, inst); break; case VM_SRC: src(context, inst, program); break; case VM_DST: dst(context, really); break; case VM_STX: case VM_SET: set(context, inst, state, program); break; case VM_JMP: pc_offset = jump(context, program); break; case VM_IFF: pc_offset = iff(context, program); break; case VM_CAL: func_call(context, inst, program, NULL); break; case VM_LST: push_list(context, program); break; case VM_MAP: push_map(context, program); break; case VM_NIL: push_nil(context); break; case VM_INT: push_int(context, program); break; case VM_FLT: push_float(context, program); break; case VM_BUL: push_bool(context, program); break; case VM_STR: push_str(context, program); break; case VM_VAR: push_var(context, program); break; case VM_FNC: push_fnc(context, program); break; case VM_GET: list_get(context, really); break; case VM_PTX: case VM_PUT: list_put(context, inst, really); break; case VM_MET: method(context, program, really); break; default: vm_exit_message(context, ERROR_OPCODE); return false; } program->current += pc_offset; } if (!context->runtime) return false; done: if (!in_context) stack_pop(context->program_stack); return inst == VM_RET; }
SpMatrix operator-(const SpMatrix& lhs, const SpMatrix &rhs) { return binary_op(lhs, rhs, minus<Data>()); }
typename field<Vector>::type accumulate(Vector const & v, typename field<Vector>::type const & init_value, BinaryFunctor const & i_binary_op) { BinaryFunctor binary_op(i_binary_op); typedef typename detail::choose_accumulate_impl<Vector, BinaryFunctor&> impl_type; return impl_type::eval(v, init_value, binary_op); }
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int i = 0; zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; zend_bool collect_constants = (op_array == &ctx->script->main_op_array); while (opline < end) { switch (opline->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_POW: case ZEND_SL: case ZEND_SR: case ZEND_CONCAT: case ZEND_FAST_CONCAT: case ZEND_IS_EQUAL: case ZEND_IS_NOT_EQUAL: case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: case ZEND_BW_OR: case ZEND_BW_AND: case ZEND_BW_XOR: case ZEND_BOOL_XOR: if (ZEND_OP1_TYPE(opline) == IS_CONST && ZEND_OP2_TYPE(opline) == IS_CONST) { /* binary operation with constant operands */ binary_op_type binary_op = get_binary_op(opline->opcode); uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */ zval result; int er; if (opline->opcode == ZEND_DIV && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_LONG && Z_LVAL(ZEND_OP2_LITERAL(opline)) == 0) { /* div by 0 */ break; } er = EG(error_reporting); EG(error_reporting) = 0; /* evaluate constant expression */ if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) != SUCCESS) { EG(error_reporting) = er; break; } EG(error_reporting) = er; if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } break; case ZEND_CAST: if (ZEND_OP1_TYPE(opline) == IS_CONST && opline->extended_value != IS_ARRAY && opline->extended_value != IS_OBJECT && opline->extended_value != IS_RESOURCE) { /* cast of constant operand */ zend_uchar type = opline->result_type; uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */ zval res; res = ZEND_OP1_LITERAL(opline); zval_copy_ctor(&res); switch (opline->extended_value) { case IS_NULL: convert_to_null(&res); break; case _IS_BOOL: convert_to_boolean(&res); break; case IS_LONG: convert_to_long(&res); break; case IS_DOUBLE: convert_to_double(&res); break; case IS_STRING: convert_to_string(&res); break; } if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } else if (opline->extended_value == _IS_BOOL) { /* T = CAST(X, IS_BOOL) => T = BOOL(X) */ opline->opcode = ZEND_BOOL; opline->extended_value = 0; } break; case ZEND_BW_NOT: case ZEND_BOOL_NOT: if (ZEND_OP1_TYPE(opline) == IS_CONST) { /* unary operation on constant operand */ unary_op_type unary_op = get_unary_op(opline->opcode); zval result; uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */ int er; er = EG(error_reporting); EG(error_reporting) = 0; if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) { EG(error_reporting) = er; break; } EG(error_reporting) = er; if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } break; #if 0 case ZEND_ADD_STRING: case ZEND_ADD_CHAR: { zend_op *next_op = opline + 1; int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0); size_t final_length = 0; zend_string *str; char *ptr; zend_op *last_op; /* There is always a ZEND_RETURN at the end if (next_op>=end) { break; } */ while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) { if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) { break; } if (next_op->opcode == ZEND_ADD_CHAR) { final_length += 1; } else { /* ZEND_ADD_STRING */ final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op)); } next_op++; } if (final_length == 0) { break; } last_op = next_op; final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline))); str = zend_string_alloc(final_length, 0); str->len = final_length; ptr = str->val; ptr[final_length] = '\0'; if (requires_conversion) { /* ZEND_ADD_CHAR */ char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline)); ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str); ptr[0] = chval; opline->opcode = ZEND_ADD_STRING; ptr++; } else { /* ZEND_ADD_STRING */ memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline))); ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline)); zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline))); ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str); } next_op = opline + 1; while (next_op < last_op) { if (next_op->opcode == ZEND_ADD_STRING) { memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op))); ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op)); literal_dtor(&ZEND_OP2_LITERAL(next_op)); } else { /* ZEND_ADD_CHAR */ *ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op)); ptr++; } MAKE_NOP(next_op); next_op++; } if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) { /* NOP removal is disabled => insert JMP over NOPs */ if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */ (opline + 1)->opcode = ZEND_JMP; ZEND_OP1(opline + 1).opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */ } } } break; #endif case ZEND_FETCH_CONSTANT: if (ZEND_OP1_TYPE(opline) == IS_UNUSED && ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 && memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) { /* substitute __COMPILER_HALT_OFFSET__ constant */ zend_execute_data *orig_execute_data = EG(current_execute_data); zend_execute_data fake_execute_data; zval *offset; memset(&fake_execute_data, 0, sizeof(zend_execute_data)); fake_execute_data.func = (zend_function*)op_array; EG(current_execute_data) = &fake_execute_data; if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) { uint32_t tv = ZEND_RESULT(opline).var; if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) { literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } EG(current_execute_data) = orig_execute_data; break; } if (ZEND_OP1_TYPE(opline) == IS_UNUSED && ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { /* substitute persistent constants */ uint32_t tv = ZEND_RESULT(opline).var; zval c; if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) { if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) { break; } } if (Z_TYPE(c) == IS_CONSTANT_AST) { break; } if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) { literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } /* class constant */ if (ZEND_OP1_TYPE(opline) != IS_UNUSED && ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { zend_class_entry *ce = NULL; if (ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { /* for A::B */ if (op_array->scope && !strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), op_array->scope->name->val, Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) { ce = op_array->scope; } else { if ((ce = zend_hash_find_ptr(EG(class_table), Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL || (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->type != MODULE_PERSISTENT) || (ce->type == ZEND_USER_CLASS && ZEND_CE_FILENAME(ce) != op_array->filename)) { break; } } } else if (op_array->scope && ZEND_OP1_TYPE(opline) == IS_VAR && (opline - 1)->opcode == ZEND_FETCH_CLASS && (ZEND_OP1_TYPE(opline - 1) == IS_UNUSED && ((opline - 1)->extended_value & ~ZEND_FETCH_CLASS_NO_AUTOLOAD) == ZEND_FETCH_CLASS_SELF) && ZEND_RESULT((opline - 1)).var == ZEND_OP1(opline).var) { /* for self::B */ ce = op_array->scope; } if (ce) { uint32_t tv = ZEND_RESULT(opline).var; zval *c, t; if ((c = zend_hash_find(&ce->constants_table, Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL) { ZVAL_DEREF(c); if (Z_TYPE_P(c) == IS_CONSTANT_AST) { break; } if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) { if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) || ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) { break; } } else { ZVAL_COPY_VALUE(&t, c); zval_copy_ctor(&t); } if (ZEND_OP1_TYPE(opline) == IS_CONST) { literal_dtor(&ZEND_OP1_LITERAL(opline)); } else { MAKE_NOP((opline - 1)); } if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) { literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } } } break; case ZEND_DO_ICALL: { zend_op *send1_opline = opline - 1; zend_op *send2_opline = NULL; zend_op *init_opline = NULL; while (send1_opline->opcode == ZEND_NOP) { send1_opline--; } if (send1_opline->opcode != ZEND_SEND_VAL || ZEND_OP1_TYPE(send1_opline) != IS_CONST) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } if (send1_opline->op2.num == 2) { send2_opline = send1_opline; send1_opline--; while (send1_opline->opcode == ZEND_NOP) { send1_opline--; } if (send1_opline->opcode != ZEND_SEND_VAL || ZEND_OP1_TYPE(send1_opline) != IS_CONST) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } } init_opline = send1_opline - 1; while (init_opline->opcode == ZEND_NOP) { init_opline--; } if (init_opline->opcode != ZEND_INIT_FCALL || ZEND_OP2_TYPE(init_opline) != IS_CONST || Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } /* define("name", scalar); */ if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 && zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) { if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING && send2_opline && Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) { if (collect_constants) { zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline)); } if (RESULT_UNUSED(opline) && !zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) { opline->opcode = ZEND_DECLARE_CONST; opline->op1_type = IS_CONST; opline->op2_type = IS_CONST; opline->result_type = IS_UNUSED; opline->op1.constant = send1_opline->op1.constant; opline->op2.constant = send2_opline->op1.constant; opline->result.num = 0; literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); MAKE_NOP(send1_opline); MAKE_NOP(send2_opline); } break; } } /* pre-evaluate constant functions: defined(x) constant(x) function_exists(x) is_callable(x) extension_loaded(x) */ if (!send2_opline && Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) { if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "function_exists", sizeof("function_exists")-1)) || (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "is_callable", sizeof("is_callable")))) { zend_internal_function *func; zend_string *lc_name = zend_string_tolower( Z_STR(ZEND_OP1_LITERAL(send1_opline))); if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL && func->type == ZEND_INTERNAL_FUNCTION && func->module->type == MODULE_PERSISTENT) { zval t; if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 || func->handler != ZEND_FN(display_disabled_function)) { ZVAL_TRUE(&t); } else { ZVAL_FALSE(&t); } if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); zend_string_release(lc_name); break; } } zend_string_release(lc_name); } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "extension_loaded", sizeof("extension_loaded")-1)) { zval t; zend_string *lc_name = zend_string_tolower( Z_STR(ZEND_OP1_LITERAL(send1_opline))); zend_module_entry *m = zend_hash_find_ptr(&module_registry, lc_name); zend_string_release(lc_name); if (!m) { if (!PG(enable_dl)) { break; } else { ZVAL_FALSE(&t); } } else { if (m->type == MODULE_PERSISTENT) { ZVAL_TRUE(&t); } else { break; } } if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("defined")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "defined", sizeof("defined")-1)) { zval t; if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 0)) { ZVAL_TRUE(&t); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "constant", sizeof("constant")-1)) { zval t; if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) { if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } } else if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN) == 0 && Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("strlen") - 1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "strlen", sizeof("strlen") - 1)) { zval t; ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline))); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "dirname", sizeof("dirname")-1) && IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) { zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0); dirname->len = zend_dirname(dirname->val, dirname->len); if (IS_ABSOLUTE_PATH(dirname->val, dirname->len)) { zval t; ZVAL_STR(&t, dirname); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } else { zend_string_release(dirname); } } } /* don't colllect constants after any other function call */ collect_constants = 0; break; } case ZEND_STRLEN: if (ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { zval t; ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline))); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } break; case ZEND_DEFINED: { zval c; uint32_t tv = ZEND_RESULT(opline).var; if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) { break; } ZVAL_TRUE(&c); if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } break; case ZEND_DECLARE_CONST: if (collect_constants && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) { zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); } break; case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_GENERATOR_RETURN: case ZEND_EXIT: case ZEND_THROW: case ZEND_CATCH: case ZEND_BRK: case ZEND_CONT: case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_FAST_RET: case ZEND_JMP: case ZEND_JMPZNZ: case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: collect_constants = 0; break; case ZEND_FETCH_R: case ZEND_FETCH_W: case ZEND_FETCH_RW: case ZEND_FETCH_FUNC_ARG: case ZEND_FETCH_IS: case ZEND_FETCH_UNSET: if (opline != op_array->opcodes && (opline-1)->opcode == ZEND_BEGIN_SILENCE && (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL && opline->op1_type == IS_CONST && opline->op2_type == IS_UNUSED && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && (Z_STRLEN(ZEND_OP1_LITERAL(opline)) != sizeof("this")-1 || memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), "this", sizeof("this") - 1) != 0)) { int var = opline->result.var; int level = 0; zend_op *op = opline + 1; zend_op *use = NULL; while (op < end) { if (op->opcode == ZEND_BEGIN_SILENCE) { level++; } else if (op->opcode == ZEND_END_SILENCE) { if (level == 0) { break; } else { level--; } } if (op->op1_type == IS_VAR && op->op1.var == var) { if (use) { /* used more than once */ use = NULL; break; } use = op; } else if (op->op2_type == IS_VAR && op->op2.var == var) { if (use) { /* used more than once */ use = NULL; break; } use = op; } op++; } if (use) { if (use->op1_type == IS_VAR && use->op1.var == var) { use->op1_type = IS_CV; use->op1.var = zend_optimizer_lookup_cv(op_array, Z_STR(ZEND_OP1_LITERAL(opline))); MAKE_NOP(opline); } else if (use->op2_type == IS_VAR && use->op2.var == var) { use->op2_type = IS_CV; use->op2.var = zend_optimizer_lookup_cv(op_array, Z_STR(ZEND_OP1_LITERAL(opline))); MAKE_NOP(opline); } } } break; } opline++; i++; } }
Link interpret(Link codeblock_link , Link This, Link Arg){ CallEnv env = callenv_new_root( codeblock_link, This, Arg); LinkStack stack = env->stack; Link b = NULL; Link link = NULL; Link parent = NULL; Link child_key = NULL; Link pusher = NULL; // Anything in this variable gets pushed onto the stack Link trapped = NULL; // This is the last critical caught by the trap operator int delta = 0; // jump delta /* Main interpreter loop */ while(1){ switch( *(env->current++) ){ case INTRO: env->current+=4; break; case ALLOC_MODULE: delta = read_offset(env); env->module->global_vars = linkarray_new(delta); break; case ALLOC_LOCAL: delta = read_offset(env); env->local = linkarray_new(delta); break; case NO_OP: break; case RETURN: // if there is something on the env->stack stack pop it off and return it, if not return null link if ( stack_length(stack) - env->stack_offset ){ pusher = stack_pop(stack); }else{ pusher = object_create(Global->null_type); } goto done; case RAISE: // if there is something on the stack stack pop it off and return it, if not return null link if ( stack_length(stack) - env->stack_offset ){ pusher = create_critical(stack_pop(stack)); }else{ pusher = create_critical(object_create(Global->null_type)); } goto done; case PUSH_LEX: delta = read_offset(env); //fprintf(stderr , "push lex [%i] %p\n", delta,env->function->value.codeblock->lexicals); pusher = link_dup(env->function->value.codeblock->lexicals->vars[delta]); break; case STORE_LEX: delta = read_offset(env); //fprintf(stderr , "storing lex [%i] %p\n", delta,env->function->value.codeblock->lexicals); b = env->function->value.codeblock->lexicals->vars[delta]; if (b){ if ( (b->type == Global->function_type) && (b->value.codeblock->lexicals == env->function->value.codeblock->lexicals) ) b->value.codeblock->lexical_cycles--; link_free(b); } b = link_dup(stack_peek(stack)); if ( (b->type == Global->function_type) && (b->value.codeblock->lexicals == env->function->value.codeblock->lexicals) ) b->value.codeblock->lexical_cycles++; env->function->value.codeblock->lexicals->vars[delta] = b; break; case DEF: if (env->Def) link_free(env->Def); env->Def = stack_pop(env->stack); pusher = link_dup(env->Def); break; case PUSH_DEF: if ( ! env->Def){ pusher = exception("NoDefObject",NULL, NULL); } pusher = link_dup(env->Def); break; case ALLOC_LEXICAL: delta = read_offset(env); lexicals_alloc( env->function, delta); //env->lexical_root = 1; break; case STORE_ARG: delta = read_offset(env); if (env->Arg->value.array->length > delta){ retry_store_arg: env->Arg->value.array->links[delta] = link_dup( stack_peek(stack) ); }else{ array_push(env->Arg, NULL); goto retry_store_arg; } break; case PUSH_ARG: delta = read_offset(env); if (env->Arg->value.array->length > delta){ pusher = link_dup( env->Arg->value.array->links[delta]); }else{ pusher = exception("ArgsIndexOutOfBounds", NULL, NULL); } break; case STORE_GVAR: delta = read_offset(env); if (env->module->global_vars->links[delta]){ link_free(env->module->global_vars->links[delta]); } env->module->global_vars->links[delta] = link_dup( stack_peek(stack) ); break; case STORE_VAR: delta = read_offset(env); if (env->local->links[delta]){ link_free(env->local->links[delta]); } env->local->links[delta] = link_dup( stack_peek(stack) ); break; case STORE_CHILD: link = stack_pop(stack); // value child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = object_addChild(parent, link, child_key); goto STORE_COMMON; case STORE_ATTR: link = stack_pop(stack); // value child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = addAttr(parent, link,child_key); goto STORE_COMMON; STORE_COMMON: if (! pusher){ pusher = exception("AssignError", NULL, NULL); link_free(link); } link_free(child_key); link_free(parent); break; case LT: delta = compare(env); pusher = create_numberi( (delta < 0) ? 1 : 0 ); break; case GT: delta = compare(env); pusher = create_numberi( (delta > 0) ? 1 : 0 ); break; case EQ: delta = compare(env); pusher = create_numberi( (delta == 0) ? 1 : 0 ); break; case NE: delta = compare(env); pusher = create_numberi( (delta == 0) ? 0 : 1 ); break; case LE: delta = compare(env); pusher = create_numberi( (delta <= 0) ? 1 : 0 ); break; case GE: delta = compare(env); pusher = create_numberi( (delta >= 0) ? 1 : 0 ); break; case CMP: delta = compare(env); pusher = create_numberi( delta ); break; case OR: case AND: break; case SUB: b = stack_pop(env->stack); link = stack_pop(env->stack); if ( (link->type == Global->number_type) && (link->type == b->type)){ pusher = create_number(link->value.number - b->value.number); link_free(link); link_free(b); break; } pusher = object_op_minus(link,b); link_free(link); link_free(b); break; case ADD: b = stack_pop(env->stack); link = stack_pop(env->stack); if ( (link->type == Global->number_type) && (link->type == b->type)){ pusher = create_number(link->value.number + b->value.number); link_free(link); link_free(b); break; } pusher = object_op_plus(link,b); link_free(link); link_free(b); break; case DIV: binary_op(env , object_op_divide); break; case MULT: binary_op(env , object_op_multiply); break; case MOD: binary_op(env , object_op_modulus); break; case POW: binary_op(env , object_op_power); break; case NEG: unary_op(env, object_op_neg); break; case NOT: link = stack_pop(stack); pusher = create_numberi( (object_is_true(link)) ? 0 : 1 ); link_free(link); break; case TEST: case ELSE: break; case DO: delta = read_offset(env); link = codeblock_literal2( env->function->value.codeblock->parent, delta ); if (env->function->value.codeblock->lexicals) { lexicals_attach( env->function->value.codeblock->lexicals, link); } env = callenv_new_doblock(env,link); break; case PUSH_ARRAY: delta = read_offset(env); pusher = array_new_subarray( stack , delta); break; case CALL: link = stack_pop(stack); // the arguments in an array b = stack_pop(stack); // the function that gets called parent = link_dup(env->This); // caller goto CALL_COMMON; case CALL_ATTR: link = stack_pop(stack); // arguments child_key = stack_pop(stack); // name of the function parent = stack_pop(stack); // caller b = getAttr(parent,child_key); // the function that gets called link_free(child_key); // no longer need the attributes key if (! b) { pusher = exception("AttrNotFound", NULL, NULL); break; } goto CALL_COMMON; case CALL_CHILD: link = stack_pop(stack); // ARG child_key = stack_pop(stack); parent = stack_pop(stack); // THIS b = object_getChild(parent,child_key); link_free(child_key); goto CALL_COMMON; CALL_COMMON: /* function type so we can call it inline */ if (b->type == Global->function_type){ env = callenv_new_function(env, b, parent, link); // ce , func,this, arg /* Not a CodeBlock so we have to use its virtual call function */ }else{ pusher = object_call(b, parent, link);// function, caller, args link_free(link); if (parent) link_free(parent); link_free(b); if (! pusher) pusher = object_create(Global->null_type); } break; case DEL_CHILD: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in /* delete child from container */ pusher = object_delChild(parent,child_key); if (! pusher) pusher = exception("ChildNotFound", object_getString(child_key), NULL); link_free(child_key); link_free(parent); break; case DEL_ATTR: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in /* delete attr from container */ pusher = delAttr(parent,child_key); if (! pusher) pusher = exception("AttrNotFound", object_getString(child_key), NULL); link_free(child_key); link_free(parent); break; case GET_CHILD: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = object_getChild(parent, child_key); if (! pusher) pusher = exception("ChildNotFound", object_getString(child_key), NULL); link_free(parent); link_free(child_key); break; case GET_ATTR: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = getAttr(parent, child_key); if (! pusher) pusher = exception("AttrNotFound", object_getString(child_key), NULL); link_free(parent); link_free(child_key); break; case TRAP: break; case CLEAR: for ( delta = stack_length( stack ) ; delta > env->stack_offset ; delta--){ link_free( stack_pop(stack) ); } break; case STOP: break; done: case END: for ( delta = stack_length( stack ) ; delta > env->stack_offset ; delta--){ link_free( stack_pop(stack) ); } addBacktrace(pusher, env->function, env->linenum); env = callenv_free(env); if (! env) goto end; if (! pusher) pusher = object_create(Global->null_type); break; /* JUMPS */ case JIT: /* Jump if true */ delta = read_offset(env); link = stack_peek(stack); if ( link->type->is_true(link) ) env->current = env->start+delta; break; case JIF: /* Jump if false */ delta = read_offset(env); link = stack_peek(stack); if ( ! link->type->is_true(link) ) env->current = env->start+delta; break; case JIF_POP: /* Pop value then jump if value is false, */ delta = read_offset(env); link = stack_pop(stack); if ( ! link->type->is_true(link) ) env->current = env->start+delta; link_free(link); break; case JUMP: /* Absolute jump */ delta = read_offset(env); env->current = env->start + delta; break; case JINC: /* Jump If Not Critical */ delta = read_offset(env); env->current = env->start+delta; break; jinc_critical: delta = read_offset(env); if (trapped) link_free(trapped); trapped = pusher->value.link; pusher->value.link = NULL; link_free(pusher); pusher = NULL; break; case PUSH_NULL: pusher = create_null(); break; case PUSH_NUM: pusher = create_number( *((number_t *)env->current) ); env->current+= sizeof(number_t); break; case PUSH_STR: delta = read_offset(env); pusher = create_string_literal( env->start + delta ); break; case PUSH_GVAR: delta = read_offset(env); pusher = link_dup(env->module->global_vars->links[delta]); if (! pusher){ pusher = exception("GlobalVariableUsedBeforeSet",NULL,NULL); } break; case PUSH_VAR: delta = read_offset(env); pusher = link_dup(env->local->links[delta]); if (! pusher){ pusher = exception("VariableUsedBeforeSet",NULL,NULL);; } break; case PUSH_BLOCK: delta = read_offset(env); pusher = codeblock_literal2( env->function->value.codeblock->parent, delta ); if (env->function->value.codeblock->lexicals) { lexicals_attach( env->function->value.codeblock->lexicals, pusher); } break; case PUSH_SYS: pusher = link_dup(Global->SYS_MODULE); break; case PUSH_MODULE: pusher = link_dup( env->function->value.codeblock->parent); break; case TYPEOF: link = stack_pop(stack); pusher = link_dup( link->type->type_link); link_free(link); break; case PUSH_THIS: pusher = link_dup(env->This); break; case PUSH_SELF: pusher = link_dup(env->Self); break; case PUSH_ARGS: pusher = link_dup(env->Arg); break; case PUSH_TRAPPED: pusher = trapped ? link_dup(trapped) : object_create(Global->null_type); break; case POP: link_free( stack_pop(stack) ); break; case LINE: env->linenum = read_offset(env); break; default: fprintf(stderr," UNRECOGNIZED OPCODE ERROR %i\n", *(env->current)); fprintf(stderr," near line %i\n", (int)(env->linenum)); exit(1); break; } if (pusher) { if ( is_critical( pusher ) ){ if ( *(env->current) == JINC) goto jinc_critical; goto done; } stack_push(stack , pusher); pusher = NULL; } } end: if (trapped) link_free(trapped); return pusher; }