示例#1
0
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), "%");
}
示例#2
0
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);
}
示例#4
0
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];
  }
}
示例#8
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);
}
示例#9
0
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);
}
示例#11
0
		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);
}
示例#13
0
文件: codegen.c 项目: ras52/bootstrap
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] );
}
示例#14
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);
  }
}
示例#15
0
文件: qcc.c 项目: HackLinux/qcc
// 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;
}
示例#16
0
文件: vm.c 项目: smorimura/filagree
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;
}
示例#17
0
SpMatrix operator-(const SpMatrix& lhs, const SpMatrix &rhs) {
  return binary_op(lhs, rhs, minus<Data>());
}
示例#18
0
 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);
 }
示例#19
0
文件: pass1_5.c 项目: cunwang/php-src
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++;
	}
}
示例#20
0
文件: interp.c 项目: elechak/blue
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;
}