
	void CodegenMIR::emitCopy(FrameState* state, int src, int dest)
	{
		// local[dest] = local[src]
		localSet(dest, localGet(src));
	}

	void CodegenMIR::emitGetscope(FrameState* state, int scope_index, int dest)
	{
		Traits* t = info->declaringTraits->scope->scopes[scope_index].traits;
		OP* declVTable = loadIns(MIR_ldop, offsetof(MethodEnv, vtable), ldargIns(_env));
		OP* scope = loadIns(MIR_ldop, offsetof(VTable, scope), declVTable);
		OP* scopeobj = loadIns(MIR_ldop, offsetof(ScopeChain, scopes) + scope_index*sizeof(Atom), scope);
		localSet(dest, atomToNativeRep(t, scopeobj));
	}

	void CodegenMIR::emitSwap(FrameState* state, int i, int j)
	{
		OP* a = localGet(i);
		OP* b = localGet(j);
		localSet(i, b);
		localSet(j, a);
	}

	void CodegenMIR::emitKill(FrameState* state, int i)
	{
		localSet(i, undefConst);
	}

	void CodegenMIR::emitSetContext(FrameState *state, AbstractFunction *f)
	{
		if (isCodeContextChanged())
		{
 			if (!f || f->usesCallerContext())
			{
				// core->codeContext = env;
				storeIns(ldargIns(_env), (uintptr)&core->codeContextAtom, 0);
			}

			if (!f || f->usesDefaultXmlNamespace())
			{
				emitSetDxns(state);
			}
		}
	}

	void CodegenMIR::emitSetDxns(FrameState* state)
	{
		OP* dxnsAddr;

		if (info->isFlagSet(AbstractFunction::SETS_DXNS))
		{
			dxnsAddr = leaIns(0,dxns);
		}
		else
		{
			// dxnsAddr = &env->vtable->scope->defaultXmlNamespace
			OP* env = ldargIns(_env);
			OP* declVTable = loadIns(MIR_ldop, offsetof(MethodEnv, vtable), env);
			OP* scope = loadIns(MIR_ldop, offsetof(VTable, scope), declVTable);
			dxnsAddr = leaIns(offsetof(ScopeChain, defaultXmlNamespace), scope);
		}

		storeIns(dxnsAddr, (uintptr)&core->dxnsAddr, 0);
	}

	void CodegenMIR::merge(const Value& current, Value& target)
	{
	}


	void CodegenMIR::emitBlockStart(FrameState* state)
	{
		// our new extended BB now starts here, this means that any branch targets
		// should hit the next instruction our bb start instruction
		OP* bb = Ins(MIR_bb); // mark start of block
		firstCse = ip;

		// get a label for our block start and tie it to this location
		mirLabel(state->verifier->getFrameState(state->pc)->label, bb);

		lastFunctionCall = 0;  // reset location of last function call

		// If this is a backwards branch, generate an interrupt check.
		// current verifier state, includes tack pointer.
		if (interruptable && core->interrupts && state->targetOfBackwardsBranch)
		{
			if (state->insideTryBlock)
				storeIns(InsConst(state->pc), 0, _save_eip);

			OP* interrupted = loadIns(MIR_ld, (uintptr)&core->interrupted, NULL);
			OP* br = Ins(MIR_jne, binaryIns(MIR_ucmp, interrupted, InsConst(0)));
			mirPatchPtr(&br->target, interrupt_label);
		}
	}

	void CodegenMIR::emitBlockEnd(FrameState* state)
	{
		saveState();
	}

	void CodegenMIR::emitIntConst(FrameState* state, int index, uintptr c)
	{
		localSet(index, InsConst(c));
	}

	void CodegenMIR::emitDoubleConst(FrameState* state, int index, double* pd)
	{
		localSet(index, loadIns(MIR_fldop, (uintptr)pd, NULL));
	}

	void CodegenMIR::emitCoerce(FrameState* state, int loc, Traits* result)
	{
	emitPrep(OP_coerce)
	FrameState::value::traits, _env
	localSet/LocalGet,
	callIns(MIR_cm, MIR_csop, MIR_cmop, MIR_fcmop, MIR_add, MIR_sub, MIR_imul, MIR_ne, MIR_lsh, MIR_ldop)
	binaryIns, binaryFcmpIns, InsConst, i2dIns, ldargIns, loadToplevel
	loadtomRep, promoteNumberIns, atomToNativeRep
	markDead,
	AvmCore::coerce_s, AvmCore::number, AvmCore::string, AvmCore::integer_d, AvmCore::toUint32, AvmCore::boolean, AvmCore::intToString, AvmCore::uintToString, AvmCore::doubleToString
	CodegeMIR::coerce_o,
	Toplevel::coerceobj, Toplevel::coerce
	MethodEnv::coerceAtom2SO
	core->booleanString
	}

	void CodegenMIR::emitCheckNull(FrameState* state, int index)
	{
		emitPrep(OP_convert_o);
		FrameState::value::traits
		lovelGet, 
		CallIns(MIR_cm)
		Ins(MIR_jeq)
		binaryIns(MIR_ucmp)
		MethodEnv::nullcheck
		_env
		mirPatchPtr(&br->target, npe_label);
	}

	void CodegenMIR::emitPrep(AbcOpcode opcode)
	{
		storeIns
	}

	void CodegenMIR::emitCall(FrameState *state, AbcOpcode opcode, int method_id, int argc, Traits* result)
	{
		FrameState::sp
		ldargIns(_env)
		callIndirect(MIR_fci, MIR_ci)
		emitPrep(opcode);
		InsAlloc/InsDealloc
		leaIns
		offset MethodEnv::impl32
		localSet/localGet

		case OP_constructsuper:
		offset MethodEnv::vtable, VTable::base, VTable::init
		loadIns(MIR_ldop);

		case OP_callmethod:
		{
			loadVTable
			offset VTable::methods
		}
		case OP_callsuperid:
		{
			offset MethodEnv::vtable, Vtable::base, VTable::methods
		}
		case OP_callstatic:
		{
			offset MethodEnv::vtable, VTable::abcEnv, AbcEnv::methods
		}
		case OP_callinterface:
		{
			method_id
			loadVTable
			offset VTable::imt
		}
	}

	void CodegenMIR::emit(FrameState* state, AbcOpcode opcode, uintptr op1, uintptr op2, Traits* result)
	{
		this->state = state;
		emitPrep(opcode);

		int sp = state->sp();

		switch (opcode)
		{
			case OP_jump:
			{
				// spill everything first
				int targetpc = op1;

				saveState();
				
#ifdef DEBUGGER
				if(core->sampling() && targetpc < state->pc)
				{
					emitSampleCheck();
				}
#endif

				// relative branch
				OP* p = Ins(MIR_jmp); // will be patched

				mirPatch(p, targetpc);
				break;
			}

			case OP_lookupswitch:
			{
				saveState();

				OP* input = localGet(sp);
				OP* cmp = binaryIns(MIR_ucmp, input, InsConst(count));
				OP* p = Ins(MIR_jnlt, cmp); // will be patched
				mirPatch(p, targetpc);

				// now for non-default
				OP* offset = binaryIns(MIR_lsh, input, InsConst(2)); // const mul by 4

				//OP* target = loadIns((int)casePtr, offset);
				OP* jmpt = Ins(MIR_jmpt, offset, count); // indirect jump using jmp table

				// fill in case address entries. These are absolute bytecode offsets
				// that later we will resolve to absolute machine addresses.
				// we can't do it now because they could be forward branches
				const byte* pc = 4 + abcStart + state->pc;
      				AvmCore::readU30(pc);

				for (int i=0; i < count; i++)
				{
					int off = state->pc + AvmCore::readS24(pc+3*i);
					mirPatchPtr(&jmpt->args[i+1], off);	// patch case table 
					if (off < state->pc)
						extendLastUse(jmpt, off);
				}
				AvmAssert(sizeof(OP)==16); // jump table size calc relies on this
				ip += (count+3)/4; // skip jump table
				case_count += count;

				// don't want cse's to live past indirect jumps
				firstCse = ip;
				break;
			}

			case OP_setglobalslot:
			case OP_setslot:
			case OP_getslot:
			{
			offset MethodEnv::vtable, VTable::scope, ScopeChain::scopes, ScriptObject::vtable, VTable::traits, Traits::sizeofInstance
				MIR_cs, MIR_ldop, MIR_ld, MIR_fld, MIR_ld, MIR_addp, MIR_imm
				GC::writeBarrierRC, AvmCore::atomWriteBarrier
				leaIns, storeIns
				atomToNativeRep


			case OP_returnvoid:
			case OP_returnvalue:
			{
			localGet
			leaIns, storeIns, ldargIns(_env)
			MIR_ret
			ExceptionFrame::endTry
			Toplevel::coerce
			atomToNativeRep
			}

			case OP_typeof:
			{
			MIR_cmop,
			AvmCore::_typeof
			localSet
			}

			case OP_not:
			{
				OP* value = localGet(op1);
				OP* i3 = binaryIns(MIR_xor, value, InsConst(1));
				localSet(op1, i3);
				break;
			}

			case OP_negate:
			{
				OP* in = localGet(op1);
				OP* out = Ins(MIR_fneg, in);
				localSet(op1, out);
				break;
			}

			case OP_negate_i:
			{
				//framep[op1] = -framep[op1]
				OP* value = localGet(op1);
				OP* i2 = Ins(MIR_neg, value);  // -number  
				localSet(op1, i2);
				break;
			}

			case OP_increment:
			case OP_decrement:
			case OP_inclocal:
			case OP_declocal:
			{
				OP* in = localGet(op1);
				OP* inc = i2dIns(InsConst(op2)); // 1 or -1
				OP* out = binaryIns(MIR_fadd, in, inc);
				localSet(op1, out);
				break;
			}

			case OP_inclocal_i:
			case OP_declocal_i:
			case OP_increment_i:
			case OP_decrement_i:
			{
				OP* in = localGet(op1);
				OP* out = binaryIns(MIR_add, in, InsConst(op2));
				localSet(op1, out);
				break;
			}

			case OP_bitnot:
			{
				// *sp = core->intToAtom(~integer(*sp));
				OP* value = localGet(op1);
				OP* out = binaryIns(MIR_xor, value, InsConst(uintptr(~0)));
				localSet(op1, out);
				break;
			}

			case OP_modulo:
			{
				OP* lhs = localGet(sp-1);
				OP* rhs = localGet(sp);
				OP* out = callIns(MIR_fcsop, FUNCADDR(MathUtils::mod), 2,
					lhs, rhs);
				localSet(sp-1,	out);
				break;
			}

			case OP_add_d:
			case OP_subtract:
			case OP_subtract_i:
			case OP_add_i:
			case OP_multiply:
			case OP_multiply_i:
			case OP_divide:
			case OP_lshift:
			case OP_rshift:
			case OP_urshift:
			case OP_bitand:
			case OP_bitor:
			case OP_bitxor:
			{
				MirOpcode mircode=MIR_last;
				switch (opcode) {
					case OP_bitxor:     mircode = MIR_xor;  break;
					case OP_bitor:      mircode = MIR_or;   break;
					case OP_bitand:     mircode = MIR_and;  break;
					case OP_urshift:    mircode = MIR_ush;  break;
					case OP_rshift:     mircode = MIR_rsh;  break;
					case OP_lshift:     mircode = MIR_lsh;  break;
					case OP_divide:     mircode = MIR_fdiv; break;
					case OP_multiply:   mircode = MIR_fmul; break;
					case OP_multiply_i: mircode = MIR_imul; break;
					case OP_add_i:      mircode = MIR_add;  break;
					case OP_subtract_i: mircode = MIR_sub;  break;
					case OP_subtract:   mircode = MIR_fsub; break;
					case OP_add_d:      mircode = MIR_fadd; break;
					default: break;
				}
				OP* lhs = localGet(sp-1);
				OP* rhs = localGet(sp);
				OP* out = binaryIns(mircode, lhs, rhs);
				localSet(sp-1, out);
				break;
			}

			case OP_throw:
			{
				// flush it all out
				OP* value = loadAtomRep(op1);
				saveState();
				//throwAtom(*sp--);
				callIns(MIR_cm, COREADDR(AvmCore::throwAtom), 2,
					InsConst((uintptr)core), value);
				break;
			}

			case OP_getsuper:
			{
				// stack in: obj [ns [name]]
				// stack out: value
				// sp[0] = env->getsuper(sp[0], multiname)
				int objDisp = sp;
				OP* multi = initMultiname((Multiname*)op1, objDisp);
				AvmAssert(state->value(objDisp).notNull);

				OP* obj = loadAtomRep(objDisp);

				OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::getsuper), 3,
					ldargIns(_env), obj, leaIns(0,multi));

				InsDealloc(multi);

				i3 = atomToNativeRep(result, i3);
				localSet(objDisp, i3);
				break;
			}

			case OP_setsuper:
			{
				// stack in: obj [ns [name]] value
				// stack out: nothing
				// core->setsuper(sp[-1], multiname, sp[0], env->vtable->base)
				int objDisp = sp-1;
				OP* multi = initMultiname((Multiname*)op1, objDisp);

				OP* obj = loadAtomRep(objDisp);
				OP* value = loadAtomRep(sp);

				callIns(MIR_cm, ENVADDR(MethodEnv::setsuper), 4,
					ldargIns(_env), obj, leaIns(0, multi), value);

				InsDealloc(multi);
				break;
			}

			case OP_nextname:
			case OP_nextvalue:
			{
				// sp[-1] = next[name|value](sp[-1], sp[0]);
				OP* obj = loadAtomRep(sp-1);
				AvmAssert(state->value(sp).traits == INT_TYPE);
				OP* index = localGet(sp);
				OP* i1 = callIns(MIR_cm, (opcode == OP_nextname) ? ENVADDR(MethodEnv::nextname) : ENVADDR(MethodEnv::nextvalue), 3,
					ldargIns(_env), obj, index);
				localSet(sp-1, atomToNativeRep(result, i1));
				break;
			}

			case OP_hasnext: 
			{
				// sp[-1] = hasnext(sp[-1], sp[0]);
				OP* obj = loadAtomRep(sp-1);
				OP* index = localGet(sp);
				OP* i1 = callIns(MIR_cm, ENVADDR(MethodEnv::hasnext), 3,
					ldargIns(_env), obj, index);
				localSet(sp-1, i1);
				break;
			}

			case OP_hasnext2: 
			{
				OP* obj = InsAlloc(sizeof(Atom));
				OP* index = InsAlloc(sizeof(int));
				storeIns(loadAtomRep(op1), 0, obj);
				storeIns(localGet(op2), 0, index);
				OP* i1 = callIns(MIR_cm, ENVADDR(MethodEnv::hasnext2), 3,
									 ldargIns(_env), leaIns(0, obj), leaIns(0, index));
				localSet(op1, loadIns(MIR_ldop, 0, obj));
				localSet(op2, loadIns(MIR_ldop, 0, index));
				localSet(sp+1, i1);
				InsDealloc(obj);
				InsDealloc(index);
				break;
			}
			
			case OP_newfunction:
			{
				//sp[0] = core->newfunction(env, body, _scopeBase, scopeDepth);
 				AbstractFunction* func = pool->getMethodInfo(op1);
				int extraScopes = state->scopeDepth;

				// prepare scopechain args for call
				OP* ap = storeAtomArgs(extraScopes, state->verifier->scopeBase);

				OP* envArg = ldargIns(_env);
				OP* vtable = loadIns(MIR_ldop, offsetof(MethodEnv, vtable), envArg);
				OP* outer = loadIns(MIR_ldop, offsetof(VTable, scope), vtable);
				OP* argv = leaIns(0, ap);

				OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::newfunction), 4,
					envArg, InsConst((uintptr)func), outer, argv);

				InsDealloc(ap);

				localSet(op2, i3);
				break;
			}

			case OP_call:
			{
				// stack in: method obj arg1..N
				// sp[-argc-1] = call(env, sp[-argc], argc, ...)
				int argc = op1;
				int funcDisp = sp - argc - 1;
				int dest = funcDisp;

				// convert args to Atom[] for the call
				OP* func = loadAtomRep(funcDisp);
				OP* ap = storeAtomArgs(loadAtomRep(funcDisp+1), argc, funcDisp+2);

				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* argv = leaIns(0, ap);

				OP* i3 = callIns(MIR_cm, TOPLEVELADDR(Toplevel::op_call), 4, 
					toplevel, func, InsConst(argc), argv);

				InsDealloc(ap);

				localSet(dest, atomToNativeRep(result, i3));
				break;
			}

			case OP_callproperty:
			case OP_callproplex:
			case OP_callpropvoid:
			{
				// stack in: obj [ns [name]] arg1..N
				// stack out: result

				int argc = op2;
				// obj = sp[-argc]
				//tempAtom = callproperty(env, name, toVTable(obj), argc, ...);
				//	*(sp -= argc) = tempAtom;
				int argv = sp-argc+1;

				int baseDisp = sp-argc;
				OP* multi = initMultiname((Multiname*)op1, baseDisp);

				AvmAssert(state->value(baseDisp).notNull);

				// convert args to Atom[] for the call
				OP* base = loadAtomRep(baseDisp);
				OP* receiver = opcode == OP_callproplex ? InsConst(nullObjectAtom) : base;
				OP* ap = storeAtomArgs(receiver, argc, argv);

				OP* vtable = loadVTable(baseDisp);
				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* atomv = leaIns(0, ap);

				OP* out = callIns(MIR_cm, TOPLEVELADDR(Toplevel::callproperty), 6,
					toplevel, base, leaIns(0, multi), InsConst(argc), atomv, vtable);

				InsDealloc(ap);
				InsDealloc(multi);

				localSet(baseDisp, atomToNativeRep(result, out));
				break;
			}

			case OP_constructprop:
			{
				// stack in: obj [ns [name]] arg1..N
				// stack out: result

				int argc = op2;
				// obj = sp[-argc]
				//tempAtom = callproperty(env, name, toVTable(obj), argc, ...);
				//	*(sp -= argc) = tempAtom;
				int argv = sp-argc+1;

				int objDisp = sp-argc;
				OP* multi = initMultiname((Multiname*)op1, objDisp);
				AvmAssert(state->value(objDisp).notNull);

				// convert args to Atom[] for the call
				OP* obj = loadAtomRep(objDisp);
				OP* vtable = loadVTable(objDisp);
				OP* ap = storeAtomArgs(obj, argc, argv);

				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* atomv = leaIns(0, ap);
				OP* i3 = callIns(MIR_cm, TOPLEVELADDR(Toplevel::constructprop), 5,
					toplevel, leaIns(0, multi), InsConst(argc), atomv, vtable);

				InsDealloc(ap);
				InsDealloc(multi);

				localSet(objDisp, atomToNativeRep(result, i3));
				break;
			}

			case OP_callsuper:
			case OP_callsupervoid:
			{
				// stack in: obj [ns [name]] arg1..N
				// stack out: result
				// null check must have already happened.
				//	tempAtom = callsuper(multiname, obj, sp-argc+1, argc, vtable->base);
				int argc = op2;
				int argv = sp - argc + 1;
				int objDisp = sp - argc;
				OP* multi = initMultiname((Multiname*)op1, objDisp);
				AvmAssert(state->value(objDisp).notNull);

				// convert args to Atom[] for the call
				OP* obj = loadAtomRep(objDisp);

				OP* ap = storeAtomArgs(obj, argc, argv);

				OP* atomv = leaIns(0, ap);
				OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::callsuper), 4,
					ldargIns(_env), leaIns(0, multi), InsConst(argc), atomv);

				InsDealloc(ap);
				InsDealloc(multi);

				localSet(objDisp, atomToNativeRep(result, i3));
				break;
			}

			case OP_construct:
 			{
				// stack in: method arg1..N
				// sp[-argc] = construct(env, sp[-argc], argc, null, arg1..N)
 				int argc = op1;
 				int funcDisp = sp - argc;
 				int dest = funcDisp;

				OP* func = loadAtomRep(funcDisp);

				// convert args to Atom[] for the call
				OP* ap = storeAtomArgs(InsConst(nullObjectAtom), argc, funcDisp+1);

				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* argv = leaIns(0, ap);

				OP* i3 = callIns(MIR_cm, TOPLEVELADDR(Toplevel::op_construct), 4,
					toplevel, func, InsConst(argc), argv);

				InsDealloc(ap);

				localSet(dest, atomToNativeRep(result, i3));
				break;
 			}

			case OP_newobject:
			{
 				// result = env->op_newobject(sp, argc)
 				int argc = op1;
 				int dest = sp - (2*argc-1);
				int arg0 = dest;

				// convert args to Atom for the call[]
				OP* ap = storeAtomArgs(2*argc, arg0);

				OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::op_newobject), 3,
					ldargIns(_env), leaIns(4*(2*argc-1), ap), InsConst(argc));
				InsDealloc(ap);

				localSet(dest, ptrToNativeRep(result, i3));
				break;
			}

			case OP_newactivation:
			{
 				// result = core->newObject(env->activation, NULL);
 				int dest = sp+1;

				OP* envArg = ldargIns(_env);
				OP* activationVTable = callIns(MIR_cm, ENVADDR(MethodEnv::getActivation), 1, envArg);
				OP* activation = callIns(MIR_cm, COREADDR(AvmCore::newActivation), 3, 
										 InsConst((uintptr)core), activationVTable, InsConst(0));

				localSet(dest, ptrToNativeRep(result, activation));
				break;
			}

			case OP_newcatch:
			{
 				// result = core->newObject(env->activation, NULL);
 				int dest = sp+1;

				OP* activation = callIns(MIR_cm, ENVADDR(MethodEnv::newcatch), 2, 
										 ldargIns(_env), InsConst((uintptr)result));

				localSet(dest, ptrToNativeRep(result, activation));
				break;
			}

 			case OP_newarray:
 			{
				// sp[-argc+1] = core->arrayClass->newarray(sp-argc+1, argc)
 				int argc = op1;
 				int arg0 = sp - 1*argc+1;

				// convert array elements to Atom[]
				OP* ap = storeAtomArgs(argc, arg0);
				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* arrayClass = loadIns(MIR_ldop, offsetof(Toplevel,arrayClass), toplevel);
				OP* i3 = callIns(MIR_cm, SCRIPTADDR(ArrayClass::newarray), 3,
					arrayClass, leaIns(0,ap), InsConst(argc));
				InsDealloc(ap);

				AvmAssert(!result->isMachineType);
				localSet(arg0, i3);
				break;
 			}

			case OP_newclass:
			{
				// sp[0] = core->newclass(env, cinit, scopeBase, scopeDepth, base)
				int32 cinit = op1;
				int localindex = op2;
				int extraScopes = state->scopeDepth;

				OP* envArg = ldargIns(_env);
				OP* vtable = loadIns(MIR_ldop, offsetof(MethodEnv, vtable), envArg);
				OP* outer = loadIns(MIR_ldop, offsetof(VTable, scope), vtable);
				OP* base = localGet(localindex);

				// prepare scopechain args for call
				OP* ap = storeAtomArgs(extraScopes, state->verifier->scopeBase);
				OP* argv = leaIns(0, ap);

				OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::newclass), 5, 
					envArg, InsConst((int32)cinit), base, outer, argv);
				InsDealloc(ap);

				AvmAssert(!result->isMachineType);
				localSet(localindex, i3);
				break;
			}

			case OP_getdescendants:
			{
				// stack in: obj [ns [name]]
				// stack out: value
				//sp[0] = core->getdescendants(sp[0], name);
				int objDisp = sp;
				Multiname* multiname = (Multiname*) op1;

				OP* envArg = ldargIns(_env);
				OP* out;
				OP* multi = initMultiname(multiname, objDisp);
				OP* obj = loadAtomRep(objDisp);
				AvmAssert(state->value(objDisp).notNull);

				out = callIns(MIR_cm, ENVADDR(MethodEnv::getdescendants), 3,
					envArg, obj, leaIns(0, multi));

				InsDealloc(multi);
				localSet(objDisp, atomToNativeRep(result, out));
				break;
			}

			case OP_checkfilter:
			{
				// stack in: obj 
				// stack out: obj
				OP* envArg = ldargIns(_env);
				OP* value = loadAtomRep(op1);

				callIns(MIR_cm, ENVADDR(MethodEnv::checkfilter), 2,
					envArg, value);

				break;
			}

			case OP_findpropstrict: 
			case OP_findproperty: 
			{
				// stack in: [ns [name]]
				// stack out: obj
				// sp[1] = env->findproperty(scopeBase, scopedepth, name, strict)
				int dest = sp;
				OP* multi = initMultiname((Multiname*)op1, dest);
				dest++;
				int extraScopes = state->scopeDepth;

				// prepare scopechain args for call
				OP* ap = storeAtomArgs(extraScopes, state->verifier->scopeBase);

				OP* envArg = ldargIns(_env);
				OP* vtable = loadIns(MIR_ldop, offsetof(MethodEnv,vtable), envArg);
				OP* outer = loadIns(MIR_ldop, offsetof(VTable,scope), vtable);

				OP* withBase;
				if (state->withBase == -1)
				{
					withBase = InsConst(0);
				}
				else
				{
					withBase = leaIns(state->withBase*sizeof(Atom), ap);
				}
	
				// 		return env->findproperty(outer, argv, extraScopes, name, strict);

				OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::findproperty), 7, 
					envArg, outer, leaIns(0,ap), InsConst(extraScopes), leaIns(0, multi), 
					InsConst((int32)(opcode == OP_findpropstrict)),
					withBase);

				InsDealloc(ap);
				InsDealloc(multi);

				localSet(dest, atomToNativeRep(result, i3));
				break;
			}

			case OP_finddef: 
			{
				// stack in: 
				// stack out: obj
				// framep[op2] = env->finddef(name)
				Multiname* multiname = (Multiname*) op1;
				int dest = op2;
				OP* name = InsConst((uintptr)multiname->getName());
				OP* out;

				AvmAssert(multiname->isBinding());
				if (multiname->isNsset())
				{
					out = callIns(MIR_cmop, ENVADDR(MethodEnv::finddefNsset), 3,
						ldargIns(_env),
						InsConst((uintptr)multiname->getNsset()),
						name);
				}
				else
				{
					out = callIns(MIR_cmop, ENVADDR(MethodEnv::finddefNs), 3,
						ldargIns(_env),
						InsConst((uintptr)multiname->getNamespace()),
						name);
				}
				localSet(dest, ptrToNativeRep(result, out));
				break;
			}

			case OP_getproperty:
			{
				// stack in: obj [ns] [name]
				// stack out: value
				// obj=sp[0]
				//sp[0] = env->getproperty(obj, multiname);

				Multiname* multiname = (Multiname*)op1;
				bool attr = multiname->isAttr();
				Traits* indexType = state->value(sp).traits;
				int objDisp = sp;

				bool maybeIntegerIndex = !attr && multiname->isRtname() && multiname->contains(core->publicNamespace);

				if (maybeIntegerIndex && indexType == INT_TYPE)
				{
					OP* index = localGet(objDisp--);
					
					if (multiname->isRtns())
					{
						// Discard runtime namespace
						objDisp--;
					}
					
					Traits* objType = state->value(objDisp).traits;

					OP *value;
					if (objType == ARRAY_TYPE)
					{
						value = callIns(MIR_cm, ARRAYADDR(ArrayObject::_getIntProperty), 2,
							localGet(sp-1), index);
					}
					else
					{
						value = callIns(MIR_cm, ENVADDR(MethodEnv::getpropertylate_i), 3,
							ldargIns(_env), loadAtomRep(sp-1), index);
					}

					localSet(sp-1, atomToNativeRep(result, value));
				}
				else if (maybeIntegerIndex && indexType == UINT_TYPE)
				{
					OP* index = localGet(objDisp--);
					
					if (multiname->isRtns())
					{
						// Discard runtime namespace
						objDisp--;
					}
					
					Traits* objType = state->value(objDisp).traits;

					OP *value;
					if (objType == ARRAY_TYPE)
					{
						value = callIns(MIR_cm, ARRAYADDR(ArrayObject::_getUintProperty), 2,
							localGet(sp-1), index);
					}
					else
					{
						value = callIns(MIR_cm, ENVADDR(MethodEnv::getpropertylate_u), 3,
							ldargIns(_env), loadAtomRep(sp-1), index);
					}

					localSet(sp-1, atomToNativeRep(result, value));
				}
				else if (maybeIntegerIndex && indexType != STRING_TYPE)
				{
					OP* _tempname = InsAlloc(sizeof(Multiname));

					// copy the flags
					OP* mFlag = InsConst(multiname->ctFlags());
					storeIns(mFlag, offsetof(Multiname,flags), _tempname);

					OP* index = loadAtomRep(objDisp--);
					AvmAssert(state->value(objDisp).notNull);

					OP* obj = loadAtomRep(objDisp);

					// copy the compile-time namespace to the temp multiname
					OP* mSpace = InsConst((uintptr)multiname->ns);
					storeIns(mSpace, offsetof(Multiname, ns), _tempname);

					OP *multi = leaIns(0, _tempname);

					OP* value = callIns(MIR_cm, ENVADDR(MethodEnv::getpropertyHelper), 5,
									    ldargIns(_env), obj, multi, loadVTable(objDisp), index);

					InsDealloc(_tempname);

					localSet(objDisp, atomToNativeRep(result, value));
				}
				else
				{
					OP* multi = initMultiname((Multiname*)op1, objDisp);
					AvmAssert(state->value(objDisp).notNull);

					OP* vtable = loadVTable(objDisp);
					OP* obj = loadAtomRep(objDisp);
					OP* toplevel = loadToplevel(ldargIns(_env));

					//return toplevel->getproperty(obj, name, toplevel->toVTable(obj));
					OP* value = callIns(MIR_cm, TOPLEVELADDR(Toplevel::getproperty), 4,
										toplevel, obj, leaIns(0, multi), vtable);

					InsDealloc(multi);

					localSet(objDisp, atomToNativeRep(result, value));
				}
				break;
			}

			case OP_initproperty:
			case OP_setproperty:
			{
				// stack in: obj [ns] [name] value
				// stack out:
				// obj = sp[-1]
				//env->setproperty(obj, multiname, sp[0], toVTable(obj));
				OP* value = loadAtomRep(sp);

				Multiname* multiname = (Multiname*)op1;
				bool attr = multiname->isAttr();
				Traits* indexType = state->value(sp-1).traits;
				int objDisp = sp-1;

				bool maybeIntegerIndex = !attr && multiname->isRtname() && multiname->contains(core->publicNamespace);

				if (maybeIntegerIndex && indexType == INT_TYPE)
				{
					OP* index = localGet(objDisp--);
					
					if (multiname->isRtns())
					{
						// Discard runtime namespace
						objDisp--;
					}
					
					Traits* objType = state->value(objDisp).traits;

					if (objType == ARRAY_TYPE)
					{
						callIns(MIR_cm, ARRAYADDR(ArrayObject::_setIntProperty), 3,
							localGet(objDisp), index, value);
					}
					else
					{
						callIns(MIR_cm, ENVADDR(MethodEnv::setpropertylate_i), 4,
							ldargIns(_env), loadAtomRep(objDisp), index, value);
					}
				}
				else if (maybeIntegerIndex && indexType == UINT_TYPE)
				{
					OP* index = localGet(objDisp--);
					
					if (multiname->isRtns())
					{
						// Discard runtime namespace
						objDisp--;
					}
					
					Traits* objType = state->value(objDisp).traits;

					if (objType == ARRAY_TYPE)
					{
						callIns(MIR_cm, ARRAYADDR(ArrayObject::_setUintProperty), 3,
							localGet(objDisp), index, value);
					}
					else
					{
						callIns(MIR_cm, ENVADDR(MethodEnv::setpropertylate_u), 4,
							ldargIns(_env), loadAtomRep(objDisp), index, value);
					}
				}
				else if (maybeIntegerIndex)
				{
					OP* _tempname = InsAlloc(sizeof(Multiname));

					// copy the flags
					OP* mFlag = InsConst(multiname->ctFlags());
					storeIns(mFlag, offsetof(Multiname,flags), _tempname);

					OP* index = loadAtomRep(objDisp--);
					AvmAssert(state->value(objDisp).notNull);

					OP* vtable = loadVTable(objDisp);
					OP* obj = loadAtomRep(objDisp);
					OP* envarg = ldargIns(_env);

					// copy the compile-time namespace to the temp multiname
					OP* mSpace = InsConst((uintptr)multiname->ns);
					storeIns(mSpace, offsetof(Multiname, ns), _tempname);

					OP *multi = leaIns(0, _tempname);

					int func = opcode==OP_setproperty ? ENVADDR(MethodEnv::setpropertyHelper) :
														ENVADDR(MethodEnv::initpropertyHelper);
					callIns(MIR_cm, func, 6,
							envarg, obj, multi, value, vtable, index);

					InsDealloc(_tempname);

					localSet(objDisp, atomToNativeRep(result, value));
				}
				else
				{
					OP* multi = initMultiname((Multiname*)op1, objDisp);
					AvmAssert(state->value(objDisp).notNull);

					OP* vtable = loadVTable(objDisp);
					OP* obj = loadAtomRep(objDisp);
					OP* envarg = ldargIns(_env);

					if (OP_setproperty)
					{
						OP* toplevel = loadToplevel(envarg);
						callIns(MIR_cm, TOPLEVELADDR(Toplevel::setproperty), 5,
										toplevel, obj, leaIns(0, multi), value, vtable);
					}
					else
					{
						callIns(MIR_cm, ENVADDR(MethodEnv::initproperty), 5,
							envarg, obj, leaIns(0, multi), value, vtable);
					}

					InsDealloc(multi);
				}
				break;
			}

			case OP_deleteproperty:
			{
				// stack in: obj [ns] [name]
				// stack out: Boolean
				//sp[0] = delproperty(sp[0], multiname);
				int objDisp = sp;
				Multiname *multiname = (Multiname*)op1;
				if(!multiname->isRtname()) {
					OP* multi = initMultiname(multiname, objDisp, true);

					OP* obj = loadAtomRep(objDisp);
					
					OP* i3 = callIns(MIR_cm, ENVADDR(MethodEnv::delproperty), 3,
						ldargIns(_env), obj, leaIns(0, multi));

					InsDealloc(multi);

					localSet(objDisp, atomToNativeRep(result, i3));
				} else {
					OP* _tempname = InsAlloc(sizeof(Multiname));

					// copy the flags
					OP* mFlag = InsConst(multiname->ctFlags());
					storeIns(mFlag, offsetof(Multiname,flags), _tempname);

					OP* index = loadAtomRep(objDisp--);

					if( !multiname->isRtns() )
					{
						// copy the compile-time namespace to the temp multiname
						OP* mSpace = InsConst((uintptr)multiname->ns);
						storeIns(mSpace, offsetof(Multiname, ns), _tempname);
					}
					else
					{
						// intern the runtime namespace and copy to the temp multiname
						OP* nsAtom = loadAtomRep(objDisp--);
						OP* internNs = callIns(MIR_cm, ENVADDR(MethodEnv::internRtns), 2,
							ldargIns(_env), nsAtom);

						storeIns(internNs, offsetof(Multiname,ns), _tempname);
					}

					AvmAssert(state->value(objDisp).notNull);
					OP* obj = loadAtomRep(objDisp);

					OP *multi = leaIns(0, _tempname);

					OP* value = callIns(MIR_cm, ENVADDR(MethodEnv::delpropertyHelper), 4,
									    ldargIns(_env), obj, multi, index);

					InsDealloc(_tempname);

					localSet(objDisp, atomToNativeRep(result, value));
				}
				break;
			}

			case OP_convert_s:
			{
				localSet(op1, callIns(MIR_cm, COREADDR(AvmCore::string), 2,
					InsConst((uintptr)core), loadAtomRep(op1)));
				break;
			}

			case OP_esc_xelem: // ToXMLString will call EscapeElementValue
			{
				//sp[0] = core->ToXMLString(sp[0]);
				OP* value = loadAtomRep(op1);
				OP* i3 = callIns(MIR_cmop, COREADDR(AvmCore::ToXMLString), 2,
					InsConst((uintptr)core), value);
				AvmAssert(result == STRING_TYPE);
				localSet(op1, i3);
				break;
			}

			case OP_esc_xattr:
			{
				//sp[0] = core->EscapeAttributeValue(sp[0]);
				OP* value = loadAtomRep(op1);
				OP* i3 = callIns(MIR_cmop, COREADDR(AvmCore::EscapeAttributeValue), 2,
					InsConst((uintptr)core), value);
				AvmAssert(result == STRING_TYPE);
				localSet(op1, i3);
				break;
			}

			case OP_astype:
			{
				// sp[0] = core->astype(sp[0], traits)
				OP* obj = loadAtomRep(op2);
				OP* i1 = callIns(MIR_cmop, ENVADDR(MethodEnv::astype), 3,
					ldargIns(_env),
					obj,
					InsConst(op1)); // traits

				i1 = atomToNativeRep(result, i1);
				localSet(op2, i1);
				break;
			}

			case OP_astypelate:
			{
				//sp[-1] = astype(sp[-1], toClassITraits(sp[0]));
				//sp--;
				OP* type = loadAtomRep(sp);

				OP* envarg = ldargIns(_env);
				OP* itraits = callIns(MIR_cmop, ENVADDR(MethodEnv::toClassITraits), 2,
					envarg, type);

				OP* obj = loadAtomRep(sp-1);

				OP* i3 = callIns(MIR_cmop, ENVADDR(MethodEnv::astype), 3,
					envarg, obj, itraits);

				i3 = atomToNativeRep(result, i3);
				localSet(sp-1, i3);
				break;
			}


			case OP_add:
			{
				OP* lhs = loadAtomRep(sp-1);
				OP* rhs = loadAtomRep(sp);
				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* out = callIns(MIR_cm, TOPLEVELADDR(Toplevel::add2), 3,
					toplevel, lhs, rhs);
				localSet(sp-1, atomToNativeRep(result, out));
				break;
			}

			case OP_concat:
			{
				OP* lhs = localGet(sp-1);
				OP* rhs = localGet(sp);
				OP* out = callIns(MIR_cmop, COREADDR(AvmCore::concatStrings), 3,
					InsConst((uintptr)core), lhs, rhs);
				localSet(sp-1,	out);
				break;
			}

			case OP_equals:
			{
				AvmAssert(result == BOOLEAN_TYPE);
				localSet(sp-1, Ins(MIR_eq, cmpEq(COREADDR(AvmCore::eq), sp-1, sp)));
				break;
			}

			case OP_strictequals:
			{
				AvmAssert(result == BOOLEAN_TYPE);
				localSet(sp-1, Ins(MIR_eq, cmpEq(COREADDR(AvmCore::stricteq), sp-1, sp)));
				break;
			}

			case OP_lessthan:
			{
				AvmAssert(result == BOOLEAN_TYPE);
				localSet(sp-1, Ins(MIR_lt, cmpLt(sp-1, sp)));
				break;
			}

			case OP_lessequals:
			{
				AvmAssert(result == BOOLEAN_TYPE);
				localSet(sp-1, Ins(MIR_le, cmpLe(sp-1, sp)));
				break;
			}

			case OP_greaterthan:
			{
				AvmAssert(result == BOOLEAN_TYPE);
				localSet(sp-1, Ins(MIR_lt, cmpLt(sp, sp-1)));
				break;
			}

			case OP_greaterequals: 
			{
				AvmAssert(result == BOOLEAN_TYPE);
				localSet(sp-1, Ins(MIR_le, cmpLe(sp, sp-1)));
				break;
			}

			case OP_instanceof:
			{
				OP* lhs = loadAtomRep(sp-1);
				OP* rhs = loadAtomRep(sp);
				OP* toplevel = loadToplevel(ldargIns(_env));
				OP* out = callIns(MIR_cm, TOPLEVELADDR(Toplevel::instanceof), 3,
					toplevel, lhs, rhs);
				out = atomToNativeRep(result, out);
				localSet(sp-1,	out);
				break;
			}

			case OP_in:
			{
				OP* lhs = loadAtomRep(sp-1);
				OP* rhs = loadAtomRep(sp);
				OP* out = callIns(MIR_cm, ENVADDR(MethodEnv::in), 3,
					ldargIns(_env), lhs, rhs);
				out = atomToNativeRep(result, out);
				localSet(sp-1, out);
				break;
			}

			case OP_istype:
			{			
				// expects a CONSTANT_Multiname cpool index
				// used when operator "is" RHS is a compile-time type constant
				//sp[0] = istype(sp[0], itraits);
				OP* obj = loadAtomRep(op2);
				OP* itraits = InsConst(op1);
				OP* out = callIns(MIR_cm, COREADDR(AvmCore::istypeAtom), 3,
					InsConst((uintptr)core), obj, itraits);
				out = atomToNativeRep(result, out);
				localSet(op2, out);
				break;
			}

			case OP_istypelate:
			{
				//sp[-1] = istype(sp[-1], toClassITraits(sp[0]));
				//sp--;
				OP* type = loadAtomRep(sp);

				OP* traits = callIns(MIR_cmop, ENVADDR(MethodEnv::toClassITraits), 2,
					ldargIns(_env), type);

				OP* obj = loadAtomRep(sp-1);

				OP* i3 = callIns(MIR_cm, COREADDR(AvmCore::istypeAtom), 3,
					InsConst((uintptr)core), obj, traits);

				i3 = atomToNativeRep(result, i3);
				localSet(sp-1, i3);
				break;
			}

			case OP_dxns:
			{
				OP* uri = InsConst(op1); // uri
				OP* ns = callIns(MIR_cm, 
					COREADDR(AvmCore::newPublicNamespace), 
					2, 
					InsConst((uintptr)core), 
					uri);
				storeIns(ns, 0, dxns);
				break;
			}

			case OP_dxnslate:
			{
				OP* atom = loadAtomRep(op1);				
				OP* uri = callIns(MIR_cm, COREADDR(AvmCore::intern), 2,
					InsConst((uintptr)core), atom);
				OP* ns = callIns(MIR_cm, 
					COREADDR(AvmCore::newPublicNamespace), 
					2, 
					InsConst((uintptr)core), 
					uri);
				storeIns(ns, 0, dxns);
				break;
			}

			/*
			 * debugger instructions 
			 */
#ifdef DEBUGGER
			case OP_debugfile:
			{
				// todo refactor api's so we don't have to pass argv/argc
				OP* debugger = loadIns(MIR_ldop, offsetof(AvmCore, debugger),
											InsConst((uintptr)core));
				callIns(MIR_cm, DEBUGGERADDR(Debugger::debugFile), 2,
						debugger,
						InsConst(op1));
				break;
		    }

			case OP_debugline:
			{
				// todo refactor api's so we don't have to pass argv/argc
				OP* debugger = loadIns(MIR_ldop, offsetof(AvmCore, debugger),
											InsConst((uintptr)core));
				callIns(MIR_cm, DEBUGGERADDR(Debugger::debugLine), 2,
						debugger,
						InsConst(op1));
				break;
			}
#endif // DEBUGGER

			default:
			{
				AvmAssert(false); // unsupported
			}
		}

	} // emit()

	void CodegenMIR::emitIf(FrameState *state, AbcOpcode opcode, int target, int a, int b)
	{
		this->state = state;

#ifdef AVMPLUS_PROFILE
		DynamicProfiler::StackMark mark(OP_codegenop, &core->dprof);
		if (core->dprof.dprofile)
		{
			callIns(MIR_cm, PROFADDR(DynamicProfiler::mark), 1,
				(uintptr)&core->dprof, InsConst(opcode));
		}
#endif /* AVMPLUS_PROFILE */

#ifdef DEBUGGER
		if(core->sampling() && target < state->pc)
		{
			emitSampleCheck();
		}
#endif

		// 
		// compile instructions that cannot throw exceptions before we add exception handling logic
		//

		// op1 = abc opcode target
		// op2 = what local var contains condition

		// spill all, dont include cond since it gets consumed
		// UBER IMPORTANT we need to spill prior to compare since
		// mir MD generations needs compare and branch to be adjacent.
		OP* cond;
		MirOpcode br;
		
		switch (opcode)
		{
		case OP_iftrue:
			br = MIR_jne;
			cond = binaryIns(MIR_icmp, localGet(a), InsConst(0));
			break;
		case OP_iffalse:
			br = MIR_jeq;
			cond = binaryIns(MIR_icmp, localGet(a), InsConst(0));
			break;
		case OP_iflt:
			br = MIR_jlt;
			cond = cmpLt(a, b);
			break;
		case OP_ifnlt:
			br = MIR_jnlt;
			cond = cmpLt(a, b);
			break;
		case OP_ifle:
			br = MIR_jle;
			cond = cmpLe(a, b);
			break;
		case OP_ifnle:
			br = MIR_jnle;
			cond = cmpLe(a, b);
			break;
		case OP_ifgt:  // a>b === b<a
			br = MIR_jlt;
			cond = cmpLt(b, a);
			break;
		case OP_ifngt: // !(a>b) === !(b<a)
			br = MIR_jnlt;
			cond = cmpLt(b, a);
			break;
		case OP_ifge:  // a>=b === b<=a
			br = MIR_jle;
			cond = cmpLe(b, a);
			break;
		case OP_ifnge: // !(a>=b) === !(a<=b)
			br = MIR_jnle;
			cond = cmpLe(b, a);
			break;
		case OP_ifeq:
			br = MIR_jeq;
			cond = cmpEq(COREADDR(AvmCore::eq), a, b);
			break;
		case OP_ifne:
			br = MIR_jne;
			cond = cmpEq(COREADDR(AvmCore::eq), a, b);
			break;
		case OP_ifstricteq:
			br = MIR_jeq;
			cond = cmpEq(COREADDR(AvmCore::stricteq), a, b);
			break;
		case OP_ifstrictne:
			br = MIR_jne;
			cond = cmpEq(COREADDR(AvmCore::stricteq), a, b);
			break;
		default:
			AvmAssert(false);
			return;
		}

		saveState();

		OP* p = Ins(br, cond); // will be patched

		mirPatch(p, target);
	} // emitIf()
