Program: 45377
Project: 45377
Buggy source:
/** 
 * visit a single expression.  compute it's type and constant value.  If either change, add any dependents to the appropriate work list.
 * @param m
 * @param e
 * @param values
 * @param types
 * @param flowWork
 * @param ssaWork
 * @param uses
 */
void sccp_eval(Method m,Expr e,Map<Expr,Object> values,Map<Expr,Typeref> types,Set<Edge> flowWork,Set<Expr> ssaWork,EdgeMap<Expr> uses){
  Object v=null;
  Typeref tref=null;
  if (e.op == OP_phi) {
    for (    Expr a : e.args) {
      Object av=values.get(a);
      if (av == null)       continue;
      if (v == null)       v=av;
 else       if (!av.equals(v))       v=BOTTOM;
      Typeref aref=types.get(a);
      if (tref == null)       tref=aref;
 else       if (!tref.equals(aref))       tref=mdb(tref,aref);
    }
  }
 else {
    for (    Expr a : e.args)     if (!values.containsKey(a))     return;
    for (    Expr a : e.scopes)     if (!values.containsKey(a))     return;
    for (    Expr a : e.locals)     if (!values.containsKey(a))     return;
    v=BOTTOM;
    tref=ANY.ref;
switch (e.op) {
default :
      System.err.println("String_Node_Str" + e.op + "String_Node_Str"+ opNames[e.op]);
    assert(false);
case OP_hasnext2_o:
case OP_nextname:
case OP_nextvalue:
case OP_call:
case OP_callsuper:
case OP_getsuper:
case OP_getdescendants:
  break;
case OP_convert_o:
{
  tref=types.get(e.args[0]).nonnull();
  v=values.get(e.args[0]);
  break;
}
case OP_esc_xattr:
case OP_esc_xelem:
tref=STRING.ref.nonnull();
break;
case OP_newcatch:
tref=m.handlers[e.imm[0]].activation;
break;
case OP_newobject:
tref=OBJECT.ref.nonnull();
break;
case OP_newarray:
tref=ARRAY.ref.nonnull();
break;
case OP_newactivation:
tref=m.activation;
break;
case OP_getglobalscope:
if (m.cx.scopes.length > 0) {
tref=m.cx.scopes[0];
}
 else {
v=values.get(e.scopes[0].args[0]);
tref=types.get(e.scopes[0].args[0]);
}
break;
case OP_getscopeobject:
v=values.get(e.scopes[0].args[0]);
tref=types.get(e.scopes[0].args[0]);
if (tref == null) {
tref=ANY.ref;
}
break;
case OP_newclass:
tref=e.c.ref.nonnull();
break;
case OP_newfunction:
tref=FUNCTION.ref.nonnull();
break;
case OP_finddef:
if (globals.contains(e.ref)) tref=globals.get(e.ref);
break;
case OP_findpropstrict:
case OP_findproperty:
{
int i=findInner(e.ref,e.scopes,types);
if (i >= 0) {
v=values.get(e.scopes[i]);
tref=types.get(e.scopes[i]);
}
 else if ((i=findOuter(e.ref,m.cx.scopes)) >= 0) {
tref=m.cx.scopes[i];
}
 else if (globals.contains(e.ref)) {
tref=globals.get(e.ref);
}
 else {
if (m.cx.scopes.length > 0) {
tref=m.cx.scopes[0];
}
 else {
v=values.get(e.scopes[0]);
tref=types.get(e.scopes[0]);
}
}
break;
}
case OP_getlex:
{
int i=findInner(e.ref,e.scopes,types);
Typeref stref=i >= 0 ? types.get(e.scopes[i]) : (i=findOuter(e.ref,m.cx.scopes)) >= 0 ? m.cx.scopes[i] : globals.contains(e.ref) ? globals.get(e.ref) : m.cx.scopes.length > 0 ? m.cx.scopes[0] : types.get(e.scopes[0]);
Binding b=stref.t.findGet(e.ref);
if (isSlot(b)) {
tref=b.type;
if (isConst(b) && defaultValueChanged(b)) v=b.value;
}
 else if (isMethod(b)) {
tref=FUNCTION.ref.nonnull();
}
 else if (isGetter(b)) {
tref=b.method.returns;
}
break;
}
case OP_construct:
{
tref=OBJECT.ref.nonnull();
break;
}
case OP_constructprop:
{
Type ot=type(types,e.args[0]);
Binding b=ot.findGet(e.ref);
if (b != null && b.type != null && b.type.t.itype != null) {
tref=b.type.t.itype.ref.nonnull();
break;
}
break;
}
case OP_callproperty:
case OP_callproplex:
{
Type ot=type(types,e.args[0]);
Binding b=ot.findGet(e.ref);
if (isMethod(b)) {
tref=b.method.returns;
}
 else if (isSlot(b) && b.type != null) {
if (b.type.t.itype == INT) {
tref=INT.ref;
v=eval_convert_i(values.get(e.args[1]));
}
 else if (b.type.t.itype == UINT) {
tref=UINT.ref;
v=eval_convert_u(values.get(e.args[1]));
}
 else if (b.type.t.itype == STRING) {
tref=STRING.ref.nonnull();
v=eval_convert_s(values.get(e.args[1]));
}
 else if (b.type.t.itype == BOOLEAN) {
tref=BOOLEAN.ref;
v=eval_convert_b(values.get(e.args[1]));
}
 else if (b.type.t.itype == NUMBER) {
tref=NUMBER.ref;
v=eval_convert_d(values.get(e.args[1]));
}
}
break;
}
case OP_applytype:
tref=types.get(e.args[0]).nonnull();
break;
case OP_callstatic:
tref=e.m.returns;
break;
case OP_arg:
if (e.imm[0] < m.params.length) tref=m.params[e.imm[0]];
 else if (m.needsArguments() || m.needsRest() && e.imm[0] == m.params.length) tref=ARRAY.ref.nonnull();
 else tref=VOID.ref;
break;
case OP_xarg:
tref=m.handlers[e.imm[0]].type;
break;
case OP_getslot:
{
Type t0=type(types,e.args[0]);
Binding b=t0.findSlot(e.imm[0]);
if (b != null) tref=b.type;
break;
}
case OP_getproperty:
{
Type t0=type(types,e.args[0]);
Binding b=t0.findGet(e.ref);
if (isSlot(b)) {
tref=b.type;
if (isConst(b) && defaultValueChanged(b)) v=b.value;
}
 else if (isMethod(b)) {
tref=FUNCTION.ref.nonnull();
}
 else if (isGetter(b)) {
tref=b.method.returns;
}
break;
}
case OP_pushundefined:
v=e.value;
tref=VOID.ref;
break;
case OP_pushnull:
v=e.value;
tref=NULL.ref;
break;
case OP_pushtrue:
case OP_pushfalse:
v=e.value;
tref=BOOLEAN.ref;
break;
case OP_pushbyte:
case OP_pushshort:
case OP_pushint:
v=e.value;
tref=INT.ref;
break;
case OP_pushuint:
v=e.value;
tref=UINT.ref;
break;
case OP_pushstring:
v=e.value;
tref=STRING.ref.nonnull();
break;
case OP_pushnan:
case OP_pushdouble:
v=e.value;
tref=NUMBER.ref;
break;
case OP_pushnamespace:
v=e.value;
tref=NAMESPACE.ref.nonnull();
break;
case OP_jump:
flowWork.add(e.succ[0]);
return;
case OP_lookupswitch:
{
Object v1=values.get(e.args[0]);
if (v1 == BOTTOM) for (Edge s : e.succ) flowWork.add(s);
 else {
int i=intValue(v1);
if (i < 0 || i >= e.succ.length - 1) i=e.succ.length - 1;
flowWork.add(e.succ[i]);
}
return;
}
case OP_iffalse:
case OP_iftrue:
{
Object v1=values.get(e.args[0]);
if (v1 == BOTTOM) {
flowWork.add(e.succ[0]);
flowWork.add(e.succ[1]);
}
 else if (e.op == OP_iffalse) flowWork.add(e.succ[booleanValue(v1) ? 0 : 1]);
 else if (e.op == OP_iftrue) flowWork.add(e.succ[booleanValue(v1) ? 1 : 0]);
return;
}
case OP_pushscope:
case OP_pushwith:
v=values.get(e.args[0]);
tref=types.get(e.args[0]).nonnull();
break;
case OP_convert_b:
tref=BOOLEAN.ref;
v=eval_convert_b(values.get(e.args[0]));
break;
case OP_not:
{
tref=BOOLEAN.ref;
Object v0=values.get(e.args[0]);
if (v0 != BOTTOM) v=booleanValue(v0) ? FALSE : TRUE;
break;
}
case OP_deleteproperty:
case OP_deldescendants:
case OP_hasnext:
case OP_hasnext2:
case OP_equals:
case OP_strictequals:
case OP_in:
case OP_istype:
case OP_istypelate:
case OP_instanceof:
tref=BOOLEAN.ref;
break;
case OP_lessthan:
case OP_lessequals:
case OP_greaterthan:
case OP_greaterequals:
{
tref=BOOLEAN.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0.equals(NAN) || v0 == UNDEFINED || v1.equals(NAN) || v1 == UNDEFINED) v=FALSE;
 else if (v0 != BOTTOM && v1 != BOTTOM) v=e.op == OP_lessthan ? lessthan(v0,v1) : e.op == OP_lessequals ? !lessthan(v1,v0) : e.op == OP_greaterthan ? lessthan(v1,v0) : !lessthan(v0,v1);
break;
}
case OP_convert_s:
tref=STRING.ref.nonnull();
v=eval_convert_s(values.get(e.args[0]));
break;
case OP_coerce_s:
{
tref=eval_coerce_s(types.get(e.args[0]));
v=eval_coerce_s(values.get(e.args[0]));
break;
}
case OP_coerce_o:
{
Typeref t0=types.get(e.args[0]);
tref=eval_coerce_o(t0);
v=eval_coerce_o(values.get(e.args[0]),t0.t);
break;
}
case OP_coerce_a:
{
if (!(types.get(e.args[0]).equals(VOID.ref))) {
v=values.get(e.args[0]);
tref=types.get(e.args[0]);
}
 else {
tref=ANY.ref;
}
break;
}
case OP_coerce:
{
Typeref t0=types.get(e.args[0]);
Object v0=values.get(e.args[0]);
Type t=namedTypes.get(e.ref);
assert(t != null);
if (t == STRING) {
tref=eval_coerce_s(t0);
v=eval_coerce_s(v0);
}
 else if (t == OBJECT) {
tref=eval_coerce_o(t0);
v=eval_coerce_o(v0,t0.t);
}
 else if (t == INT) {
tref=t.ref;
v=eval_convert_i(v0);
}
 else if (t == UINT) {
tref=t.ref;
v=eval_convert_u(v0);
}
 else if (t == NUMBER) {
tref=t.ref;
v=eval_convert_d(v0);
}
 else if (t == BOOLEAN) {
tref=t.ref;
v=eval_convert_b(v0);
}
 else {
if (istype(t0.t,t)) {
tref=t0;
v=v0;
}
 else if (t0.t == NULL || t0.t == VOID) {
tref=NULL.ref;
}
 else {
tref=t.ref;
}
}
break;
}
case OP_astype:
tref=namedTypes.get(e.ref).ref;
break;
case OP_astypelate:
{
Typeref t1=types.get(e.args[1]);
if (t1.t.itype != null) {
if (t1.t.itype.atom || t1.t.itype.numeric) tref=OBJECT.ref;
 else tref=t1.t.itype.ref;
}
 else {
tref=ANY.ref;
}
break;
}
case OP_typeof:
{
Type t0=type(types,e.args[0]);
if (t0 == INT || t0 == UINT || t0 == NUMBER) v="String_Node_Str";
 else if (t0 == STRING) v="String_Node_Str";
 else if (istype(t0,XML) || istype(t0,XMLLIST)) v="String_Node_Str";
 else if (t0 == VOID) v="String_Node_Str";
 else if (t0 == BOOLEAN) v="String_Node_Str";
 else if (istype(t0,FUNCTION)) v="String_Node_Str";
 else if (t0 != OBJECT && istype(t0,OBJECT)) v="String_Node_Str";
tref=STRING.ref.nonnull();
break;
}
case OP_add:
{
Expr a0=e.args[0];
Expr a1=e.args[1];
Typeref t0=types.get(a0);
Typeref t1=types.get(a1);
Object v0=values.get(a0);
Object v1=values.get(a1);
if (t0.t == STRING && !t0.nullable || t1.t == STRING && !t1.nullable) {
tref=STRING.ref.nonnull();
if (v0 != BOTTOM && v1 != BOTTOM) v=stringValue(v0) + stringValue(v1);
}
 else if (t0.t.numeric && t1.t.numeric) {
tref=NUMBER.ref;
if (v0 instanceof Number && v1 instanceof Number) v=doubleValue(v0) + doubleValue(v1);
}
 else {
tref=OBJECT.ref.nonnull();
}
break;
}
case OP_divide:
{
tref=NUMBER.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0 instanceof Number && v1 instanceof Number) v=doubleValue(v0) / doubleValue(v1);
break;
}
case OP_subtract:
case OP_multiply:
case OP_modulo:
case OP_negate:
case OP_increment:
case OP_decrement:
tref=NUMBER.ref;
break;
case OP_convert_d:
tref=NUMBER.ref;
v=eval_convert_d(values.get(e.args[0]));
break;
case OP_convert_i:
tref=INT.ref;
v=eval_convert_i(values.get(e.args[0]));
break;
case OP_convert_u:
tref=UINT.ref;
v=eval_convert_u(values.get(e.args[0]));
break;
case OP_bitor:
{
tref=INT.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0 instanceof Number && v1 instanceof Number) v=intValue(v0) | intValue(v1);
break;
}
case OP_bitand:
{
tref=INT.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0 instanceof Number && v1 instanceof Number) {
v=intValue(v0) & intValue(v1);
}
break;
}
case OP_bitnot:
case OP_add_i:
case OP_subtract_i:
case OP_multiply_i:
case OP_negate_i:
case OP_bitxor:
case OP_lshift:
case OP_rshift:
case OP_hasnext2_i:
case OP_increment_i:
case OP_decrement_i:
tref=INT.ref;
break;
case OP_urshift:
tref=UINT.ref;
break;
case OP_setslot:
case OP_setproperty:
case OP_setsuper:
case OP_initproperty:
case OP_callpropvoid:
case OP_constructsuper:
case OP_callsupervoid:
case OP_returnvoid:
case OP_returnvalue:
case OP_throw:
case OP_popscope:
case OP_debug:
case OP_debugline:
case OP_debugfile:
case OP_bkpt:
case OP_bkptline:
case OP_checkfilter:
return;
}
}
assert(tref != null && tref.t != null);
if (tref.t == VOID) v=UNDEFINED;
 else if (tref.t == NULL) v=NULL;
if (v != null && !v.equals(values.get(e))) {
values.put(e,v);
ssaWork.addAll(uses.get(e));
}
if (!tref.equals(types.get(e))) {
types.put(e,tref);
ssaWork.addAll(uses.get(e));
}
}

Fixed version (ground truth):
/** 
 * visit a single expression.  compute it's type and constant value.  If either change, add any dependents to the appropriate work list.
 * @param m
 * @param e
 * @param values
 * @param types
 * @param flowWork
 * @param ssaWork
 * @param uses
 */
void sccp_eval(Method m,Expr e,Map<Expr,Object> values,Map<Expr,Typeref> types,Set<Edge> flowWork,Set<Expr> ssaWork,EdgeMap<Expr> uses){
  Object v=null;
  Typeref tref=null;
  if (e.op == OP_phi) {
    for (    Expr a : e.args) {
      Object av=values.get(a);
      if (av == null)       continue;
      if (v == null)       v=av;
 else       if (!av.equals(v))       v=BOTTOM;
      Typeref aref=types.get(a);
      if (tref == null)       tref=aref;
 else       if (!tref.equals(aref))       tref=mdb(tref,aref);
    }
  }
 else {
    for (    Expr a : e.args)     if (!values.containsKey(a))     return;
    for (    Expr a : e.scopes)     if (!values.containsKey(a))     return;
    for (    Expr a : e.locals)     if (!values.containsKey(a))     return;
    v=BOTTOM;
    tref=ANY.ref;
switch (e.op) {
default :
      System.err.println("String_Node_Str" + e.op + "String_Node_Str"+ opNames[e.op]);
    assert(false);
case OP_hasnext2_o:
case OP_nextname:
case OP_nextvalue:
case OP_call:
case OP_callsuper:
case OP_getsuper:
case OP_getdescendants:
  break;
case OP_convert_o:
{
  tref=types.get(e.args[0]).nonnull();
  v=values.get(e.args[0]);
  break;
}
case OP_esc_xattr:
case OP_esc_xelem:
tref=STRING.ref.nonnull();
break;
case OP_newcatch:
tref=m.handlers[e.imm[0]].activation;
break;
case OP_newobject:
tref=OBJECT.ref.nonnull();
break;
case OP_newarray:
tref=ARRAY.ref.nonnull();
break;
case OP_newactivation:
tref=m.activation;
break;
case OP_getglobalscope:
if (m.cx.scopes.length > 0) {
tref=m.cx.scopes[0];
}
 else {
v=values.get(e.scopes[0].args[0]);
tref=types.get(e.scopes[0].args[0]);
}
break;
case OP_getscopeobject:
v=values.get(e.scopes[0].args[0]);
tref=types.get(e.scopes[0].args[0]);
if (tref == null) {
tref=ANY.ref;
}
break;
case OP_newclass:
tref=e.c.ref.nonnull();
break;
case OP_newfunction:
tref=FUNCTION.ref.nonnull();
break;
case OP_finddef:
if (globals.contains(e.ref)) tref=globals.get(e.ref);
break;
case OP_findpropstrict:
case OP_findproperty:
{
int i=findInner(e.ref,e.scopes,types);
if (i >= 0) {
v=values.get(e.scopes[i]);
tref=types.get(e.scopes[i]);
}
 else if ((i=findOuter(e.ref,m.cx.scopes)) >= 0) {
tref=m.cx.scopes[i];
}
 else if (globals.contains(e.ref)) {
tref=globals.get(e.ref);
}
 else {
if (m.cx.scopes.length > 0) {
tref=m.cx.scopes[0];
}
 else {
v=values.get(e.scopes[0]);
tref=types.get(e.scopes[0]);
}
}
break;
}
case OP_getlex:
{
int i=findInner(e.ref,e.scopes,types);
Typeref stref=i >= 0 ? types.get(e.scopes[i]) : (i=findOuter(e.ref,m.cx.scopes)) >= 0 ? m.cx.scopes[i] : globals.contains(e.ref) ? globals.get(e.ref) : m.cx.scopes.length > 0 ? m.cx.scopes[0] : types.get(e.scopes[0]);
Binding b=stref.t.findGet(e.ref);
if (isSlot(b)) {
tref=b.type;
if (isConst(b) && defaultValueChanged(b)) v=b.value;
}
 else if (isMethod(b)) {
tref=FUNCTION.ref.nonnull();
}
 else if (isGetter(b)) {
tref=b.method.returns;
}
break;
}
case OP_construct:
{
tref=OBJECT.ref.nonnull();
break;
}
case OP_constructprop:
{
Type ot=type(types,e.args[0]);
Binding b=ot.findGet(e.ref);
if (b != null && b.type != null && b.type.t.itype != null) {
tref=b.type.t.itype.ref.nonnull();
break;
}
break;
}
case OP_callproperty:
case OP_callproplex:
{
Type ot=type(types,e.args[0]);
Binding b=ot.findGet(e.ref);
if (isMethod(b)) {
tref=b.method.returns;
}
 else if (isSlot(b) && b.type != null) {
if (b.type.t.itype == INT) {
tref=INT.ref;
if (e.args.length > 1) v=eval_convert_i(values.get(e.args[1]));
}
 else if (b.type.t.itype == UINT) {
tref=UINT.ref;
if (e.args.length > 1) v=eval_convert_u(values.get(e.args[1]));
}
 else if (b.type.t.itype == STRING) {
tref=STRING.ref.nonnull();
if (e.args.length > 1) v=eval_convert_s(values.get(e.args[1]));
}
 else if (b.type.t.itype == BOOLEAN) {
tref=BOOLEAN.ref;
if (e.args.length > 1) v=eval_convert_b(values.get(e.args[1]));
}
 else if (b.type.t.itype == NUMBER) {
tref=NUMBER.ref;
if (e.args.length > 1) v=eval_convert_d(values.get(e.args[1]));
}
}
break;
}
case OP_applytype:
tref=types.get(e.args[0]).nonnull();
break;
case OP_callstatic:
tref=e.m.returns;
break;
case OP_arg:
if (e.imm[0] < m.params.length) tref=m.params[e.imm[0]];
 else if (m.needsArguments() || m.needsRest() && e.imm[0] == m.params.length) tref=ARRAY.ref.nonnull();
 else tref=VOID.ref;
break;
case OP_xarg:
tref=m.handlers[e.imm[0]].type;
break;
case OP_getslot:
{
Type t0=type(types,e.args[0]);
Binding b=t0.findSlot(e.imm[0]);
if (b != null) tref=b.type;
break;
}
case OP_getproperty:
{
Type t0=type(types,e.args[0]);
Binding b=t0.findGet(e.ref);
if (isSlot(b)) {
tref=b.type;
if (isConst(b) && defaultValueChanged(b)) v=b.value;
}
 else if (isMethod(b)) {
tref=FUNCTION.ref.nonnull();
}
 else if (isGetter(b)) {
tref=b.method.returns;
}
break;
}
case OP_pushundefined:
v=e.value;
tref=VOID.ref;
break;
case OP_pushnull:
v=e.value;
tref=NULL.ref;
break;
case OP_pushtrue:
case OP_pushfalse:
v=e.value;
tref=BOOLEAN.ref;
break;
case OP_pushbyte:
case OP_pushshort:
case OP_pushint:
v=e.value;
tref=INT.ref;
break;
case OP_pushuint:
v=e.value;
tref=UINT.ref;
break;
case OP_pushstring:
v=e.value;
tref=STRING.ref.nonnull();
break;
case OP_pushnan:
case OP_pushdouble:
v=e.value;
tref=NUMBER.ref;
break;
case OP_pushnamespace:
v=e.value;
tref=NAMESPACE.ref.nonnull();
break;
case OP_jump:
flowWork.add(e.succ[0]);
return;
case OP_lookupswitch:
{
Object v1=values.get(e.args[0]);
if (v1 == BOTTOM) for (Edge s : e.succ) flowWork.add(s);
 else {
int i=intValue(v1);
if (i < 0 || i >= e.succ.length - 1) i=e.succ.length - 1;
flowWork.add(e.succ[i]);
}
return;
}
case OP_iffalse:
case OP_iftrue:
{
Object v1=values.get(e.args[0]);
if (v1 == BOTTOM) {
flowWork.add(e.succ[0]);
flowWork.add(e.succ[1]);
}
 else if (e.op == OP_iffalse) flowWork.add(e.succ[booleanValue(v1) ? 0 : 1]);
 else if (e.op == OP_iftrue) flowWork.add(e.succ[booleanValue(v1) ? 1 : 0]);
return;
}
case OP_pushscope:
case OP_pushwith:
v=values.get(e.args[0]);
tref=types.get(e.args[0]).nonnull();
break;
case OP_convert_b:
tref=BOOLEAN.ref;
v=eval_convert_b(values.get(e.args[0]));
break;
case OP_not:
{
tref=BOOLEAN.ref;
Object v0=values.get(e.args[0]);
if (v0 != BOTTOM) v=booleanValue(v0) ? FALSE : TRUE;
break;
}
case OP_deleteproperty:
case OP_deldescendants:
case OP_hasnext:
case OP_hasnext2:
case OP_equals:
case OP_strictequals:
case OP_in:
case OP_istype:
case OP_istypelate:
case OP_instanceof:
tref=BOOLEAN.ref;
break;
case OP_lessthan:
case OP_lessequals:
case OP_greaterthan:
case OP_greaterequals:
{
tref=BOOLEAN.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0.equals(NAN) || v0 == UNDEFINED || v1.equals(NAN) || v1 == UNDEFINED) v=FALSE;
 else if (v0 != BOTTOM && v1 != BOTTOM) v=e.op == OP_lessthan ? lessthan(v0,v1) : e.op == OP_lessequals ? !lessthan(v1,v0) : e.op == OP_greaterthan ? lessthan(v1,v0) : !lessthan(v0,v1);
break;
}
case OP_convert_s:
tref=STRING.ref.nonnull();
v=eval_convert_s(values.get(e.args[0]));
break;
case OP_coerce_s:
{
tref=eval_coerce_s(types.get(e.args[0]));
v=eval_coerce_s(values.get(e.args[0]));
break;
}
case OP_coerce_o:
{
Typeref t0=types.get(e.args[0]);
tref=eval_coerce_o(t0);
v=eval_coerce_o(values.get(e.args[0]),t0.t);
break;
}
case OP_coerce_a:
{
if (!(types.get(e.args[0]).equals(VOID.ref))) {
v=values.get(e.args[0]);
tref=types.get(e.args[0]);
}
 else {
tref=ANY.ref;
}
break;
}
case OP_coerce:
{
Typeref t0=types.get(e.args[0]);
Object v0=values.get(e.args[0]);
Type t=namedTypes.get(e.ref);
assert(t != null);
if (t == STRING) {
tref=eval_coerce_s(t0);
v=eval_coerce_s(v0);
}
 else if (t == OBJECT) {
tref=eval_coerce_o(t0);
v=eval_coerce_o(v0,t0.t);
}
 else if (t == INT) {
tref=t.ref;
v=eval_convert_i(v0);
}
 else if (t == UINT) {
tref=t.ref;
v=eval_convert_u(v0);
}
 else if (t == NUMBER) {
tref=t.ref;
v=eval_convert_d(v0);
}
 else if (t == BOOLEAN) {
tref=t.ref;
v=eval_convert_b(v0);
}
 else {
if (istype(t0.t,t)) {
tref=t0;
v=v0;
}
 else if (t0.t == NULL || t0.t == VOID) {
tref=NULL.ref;
}
 else {
tref=t.ref;
}
}
break;
}
case OP_astype:
tref=namedTypes.get(e.ref).ref;
break;
case OP_astypelate:
{
Typeref t1=types.get(e.args[1]);
if (t1.t.itype != null) {
if (t1.t.itype.atom || t1.t.itype.numeric) tref=OBJECT.ref;
 else tref=t1.t.itype.ref;
}
 else {
tref=ANY.ref;
}
break;
}
case OP_typeof:
{
Type t0=type(types,e.args[0]);
if (t0 == INT || t0 == UINT || t0 == NUMBER) v="String_Node_Str";
 else if (t0 == STRING) v="String_Node_Str";
 else if (istype(t0,XML) || istype(t0,XMLLIST)) v="String_Node_Str";
 else if (t0 == VOID) v="String_Node_Str";
 else if (t0 == BOOLEAN) v="String_Node_Str";
 else if (istype(t0,FUNCTION)) v="String_Node_Str";
 else if (t0 != OBJECT && istype(t0,OBJECT)) v="String_Node_Str";
tref=STRING.ref.nonnull();
break;
}
case OP_add:
{
Expr a0=e.args[0];
Expr a1=e.args[1];
Typeref t0=types.get(a0);
Typeref t1=types.get(a1);
Object v0=values.get(a0);
Object v1=values.get(a1);
if (t0.t == STRING && !t0.nullable || t1.t == STRING && !t1.nullable) {
tref=STRING.ref.nonnull();
if (v0 != BOTTOM && v1 != BOTTOM) v=stringValue(v0) + stringValue(v1);
}
 else if (t0.t.numeric && t1.t.numeric) {
tref=NUMBER.ref;
if (v0 instanceof Number && v1 instanceof Number) v=doubleValue(v0) + doubleValue(v1);
}
 else {
tref=OBJECT.ref.nonnull();
}
break;
}
case OP_divide:
{
tref=NUMBER.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0 instanceof Number && v1 instanceof Number) v=doubleValue(v0) / doubleValue(v1);
break;
}
case OP_subtract:
case OP_multiply:
case OP_modulo:
case OP_negate:
case OP_increment:
case OP_decrement:
tref=NUMBER.ref;
break;
case OP_convert_d:
tref=NUMBER.ref;
v=eval_convert_d(values.get(e.args[0]));
break;
case OP_convert_i:
tref=INT.ref;
v=eval_convert_i(values.get(e.args[0]));
break;
case OP_convert_u:
tref=UINT.ref;
v=eval_convert_u(values.get(e.args[0]));
break;
case OP_bitor:
{
tref=INT.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0 instanceof Number && v1 instanceof Number) v=intValue(v0) | intValue(v1);
break;
}
case OP_bitand:
{
tref=INT.ref;
Object v0=values.get(e.args[0]);
Object v1=values.get(e.args[1]);
if (v0 instanceof Number && v1 instanceof Number) {
v=intValue(v0) & intValue(v1);
}
break;
}
case OP_bitnot:
case OP_add_i:
case OP_subtract_i:
case OP_multiply_i:
case OP_negate_i:
case OP_bitxor:
case OP_lshift:
case OP_rshift:
case OP_hasnext2_i:
case OP_increment_i:
case OP_decrement_i:
tref=INT.ref;
break;
case OP_urshift:
tref=UINT.ref;
break;
case OP_setslot:
case OP_setproperty:
case OP_setsuper:
case OP_initproperty:
case OP_callpropvoid:
case OP_constructsuper:
case OP_callsupervoid:
case OP_returnvoid:
case OP_returnvalue:
case OP_throw:
case OP_popscope:
case OP_debug:
case OP_debugline:
case OP_debugfile:
case OP_bkpt:
case OP_bkptline:
case OP_checkfilter:
return;
}
}
assert(tref != null && tref.t != null);
if (tref.t == VOID) v=UNDEFINED;
 else if (tref.t == NULL) v=NULL;
if (v != null && !v.equals(values.get(e))) {
values.put(e,v);
ssaWork.addAll(uses.get(e));
}
if (!tref.equals(types.get(e))) {
types.put(e,tref);
ssaWork.addAll(uses.get(e));
}
}