package jp.kirikiri.tjs2;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

class InterCodeContext extends CustomObject {

	private static final int INC_SIZE = 256;
	private static final int INC_SIZE_BYTE = 1024;
	private static final int INC_SIZE_LONG_BYTE = 2048;

	private static final int PASS_ARGS_PREPARED_ARRAY_COUNT = 20;
	private static final int
		S_OK					= 0,
		S_TRUE					= 1,
		E_MEMBERNOTFOUND		= -1001,
		E_NOTIMPL				= -1002,
		E_INVALIDPARAM			= -1003,
		E_BADPARAMCOUNT			= -1004,
		E_INVALIDTYPE			= -1005,
		E_INVALIDOBJECT			= -1006,
		E_ACCESSDENYED			= -1007,
		E_NATIVECLASSCRASH		= -1008;

	private static final int
		MEMBERENSURE		= 0x00000200, // create a member if not exists
		MEMBERMUSTEXIST     = 0x00000400, // member *must* exist ( for Dictionary/Array )
		IGNOREPROP			= 0x00000800, // ignore property invoking
		HIDDENMEMBER		= 0x00001000, // member is hidden
		STATICMEMBER		= 0x00010000, // member is not registered to the
										  // object (internal use)
		ENUM_NO_VALUE		= 0x00100000; // values are not retrieved
										  // (for EnumMembers)

	private static final int
		CII_ADD				= 0x00000001,	// register name
											// 'num' argument passed to CII is to be igonored.
		CII_GET				= 0x00000000,	// retrieve name
		CII_SET_FINALIZE	= 0x00000002,	// register "finalize" method name
											// (set empty string not to call the method)
											// 'num' argument passed to CII is to be igonored.
		CII_SET_MISSING		= 0x00000003;	// register "missing" method name.
											// the method is called when the member is not present.
											// (set empty string not to call the method)
											// 'num' argument passed to CII is to be igonored.
											// the method is to be called with three arguments;
											// get_or_set    : false for get, true for set
											// name          : member name
											// value         : value property; you must
											//               : dereference using unary '*' operator.
											// the method must return true for found, false for not-found.

	static private boolean mStrFuncInit = false;
	static private final int STRFUNC_MAX = 13;
	static private int[] mStrFuncHash = new int[STRFUNC_MAX]; // このハッシュコードは素直に hashCode() にしたほうが早いかもしれん
	static private final String mStrFuncs[] = {
		"charAt",
		"indexOf",
		"toUpperCase",
		"toLowerCase",
		"substring",
		"substr",
		"sprintf",
		"replace",
		"escape",
		"split",
		"trim",
		"reverse",
		"repeat"
	};
	static private final int
		StrMethod_charAt = 0,
		StrMethod_indexOf = 1,
		StrMethod_toUpperCase = 2,
		StrMethod_toLowerCase = 3,
		StrMethod_substring = 4,
		StrMethod_substr = 5,
		StrMethod_sprintf = 6,
		StrMethod_replace = 7,
		StrMethod_escape = 8,
		StrMethod_split = 9,
		StrMethod_trim = 10,
		StrMethod_reverse = 11,
		StrMethod_repeat = 12;

	private VectorWrap<ExprNode> mNodeToDeleteVector;
	private VectorWrap<ExprNode> mCurrentNodeVector;

	private ScriptBlock mBlock;
	private InterCodeContext mParent;
	private String mName;
	private int mContextType;
	private IntBuffer mCodeArea;
	private int mPrevSourcePos;
	private boolean mSourcePosArraySorted;
	private LongBuffer mSourcePosArray; // 上位をcodePos, 下位をsourcePos とする
	private ArrayList<Variant> mDataArea;
	private LocalNamespace mNamespace;
	private int mVariableReserveCount;
	private int mFrameBase;
	private int mMaxFrameCount;
	//private IntWrapper mTmpInt;
	private ArrayList<Integer> mJumpList;
	private boolean mAsGlobalContextMode;
	private ExprNode mSuperClassExpr;
	private VectorWrap<NestData> mNestVector;
	private Stack<ArrayArg> mArrayArgStack;
	private Stack<FuncArg> mFuncArgStack;
	private InterCodeContext mPropSetter;
	private InterCodeContext mPropGetter;
	private InterCodeContext mSuperClassGetter;
	private int mMaxVariableCount;
	private ArrayList<FixData> mFixList;
	private VectorWrap<NonLocalFunctionDecl> mNonLocalFunctionDeclVector;
	private int mFunctionRegisterCodePoint;
	private int mPrevIfExitPatch;
	private VectorWrap<Integer> mSuperClassGetterPointer;
	private int mFuncDeclArgCount;
	private int mFuncDeclUnnamedArgArrayBase;
	private int mFuncDeclCollapseBase;

	public class SubParam {
		public int mSubType;
		public int mSubFlag;
		public int mSubAddress;
		public SubParam() {
			mSubType = 0;
			mSubFlag = 0;
			mSubAddress = 0;
		}
		public SubParam(SubParam param) {
			mSubType = param.mSubType;
			mSubFlag = param.mSubFlag;
			mSubAddress = param.mSubAddress;
		}
	}

	// tNestType
	public static int
		ntBlock		= 0,
		ntWhile		= 1,
		ntDoWhile	= 2,
		ntFor		= 3,
		ntSwitch	= 4,
		ntIf		= 5,
		ntElse		= 6,
		ntTry		= 7,
		ntCatch		= 8,
		ntWith 		= 9;

	class NestData {
		int Type;
		int VariableCount;
		// union {
			boolean VariableCreated;
			// boolean IsFirstCase; 上と同じとみなす
		//};
		int RefRegister;
		int StartIP;
		int LoopStartIP;
		Vector<Integer> ContinuePatchVector;
		Vector<Integer> ExitPatchVector;
		int Patch1;
		int Patch2;
		ExprNode PostLoopExpr;

		public NestData() {
			ContinuePatchVector = new Vector<Integer>();
			ExitPatchVector = new Vector<Integer>();
		}
	}

	class FixData {
		int StartIP;
		int Size;
		int NewSize;
		boolean BeforeInsertion;
		IntBuffer Code;

		public FixData( int startip, int size, int newsize, IntBuffer code, boolean beforeinsertion) {
			StartIP = startip;
			Size = size;
			NewSize = newsize;
			Code = code;
			BeforeInsertion = beforeinsertion;
		}
		public FixData( final FixData fixdata ) {
			Code = null;
			copy( fixdata );
		}
		public void copy( final FixData fixdata ) {
			Code = null;
			StartIP = fixdata.StartIP;
			Size = fixdata.Size;
			NewSize = fixdata.NewSize;
			BeforeInsertion = fixdata.BeforeInsertion;

			ByteBuffer buff = ByteBuffer.allocateDirect(NewSize*4);
			buff.order( ByteOrder.nativeOrder() );
			IntBuffer ibuff = buff.asIntBuffer();
			ibuff.clear();
			IntBuffer tmp = fixdata.Code.duplicate();
			tmp.flip();
			ibuff.put( tmp );
			Code = ibuff;
		}
	}
	class NonLocalFunctionDecl {
		int DataPos;
		int NameDataPos;
		boolean ChangeThis;
		public NonLocalFunctionDecl( int datapos, int namedatapos, boolean changethis ){
			DataPos = datapos;
			NameDataPos = namedatapos;
			ChangeThis = changethis;
		}
	};
	//private static final int fatNormal = 0, fatExpand = 1, fatUnnamedExpand = 2;
	class FuncArgItem {
		public int Register;
		public int Type; // tTJSFuncArgType Type;
		public FuncArgItem( int reg ) {
			this( reg, fatNormal );
		}
		public FuncArgItem( int reg, int type ) {
			Register = reg;
			Type = type;
		}
	}
	class FuncArg {
		public boolean IsOmit;
		public boolean HasExpand;
		public Vector<FuncArgItem> ArgVector;
		public FuncArg() {
			IsOmit = HasExpand = false;
			ArgVector = new Vector<FuncArgItem>();
		}
	}
	class ArrayArg {
		int Object;
		int Counter;
	}

	private static final int NAMESPACE_DEFAULT_HASH_BITS = 3;
	private static int getContextHashSize( int type ) {
		switch(type)
		{
		case ContextType.TOP_LEVEL:				return 0;
		case ContextType.FUNCTION:				return 1;
		case ContextType.EXPR_FUNCTION: 		return 1;
		case ContextType.PROPERTY:				return 1;
		case ContextType.PROPERTY_SETTER:		return 0;
		case ContextType.PROPERTY_GETTER:		return 0;
		case ContextType.CLASS:					return NAMESPACE_DEFAULT_HASH_BITS;
		case ContextType.SUPER_CLASS_GETTER:	return 0;
		default:								return NAMESPACE_DEFAULT_HASH_BITS;
		}
	}

	public InterCodeContext( InterCodeContext parent, String name, ScriptBlock block, int type ) throws VariantException {
		super(getContextHashSize(type));
		super.mCallFinalize = false;

		mNodeToDeleteVector = new VectorWrap<ExprNode>();
		mCurrentNodeVector = new VectorWrap<ExprNode>();
		//mTmpInt = new IntWrapper();
		mJumpList = new ArrayList<Integer>();
		mNestVector = new VectorWrap<NestData>();
		mArrayArgStack = new Stack<ArrayArg>();
		mFuncArgStack = new Stack<FuncArg>();
		mNamespace = new LocalNamespace();
		mFixList = new ArrayList<FixData>();
		mNonLocalFunctionDeclVector = new VectorWrap<NonLocalFunctionDecl>();
		mSuperClassGetterPointer = new VectorWrap<Integer>();

		mParent = parent;

		mPropGetter = mPropSetter = mSuperClassGetter = null;

		{
			ByteBuffer buff = ByteBuffer.allocateDirect(INC_SIZE_BYTE);
			buff.order( ByteOrder.nativeOrder() );
			mCodeArea = buff.asIntBuffer();
			mCodeArea.clear();
		}
		mDataArea = new ArrayList<Variant>();

		mFrameBase = 1;

		mSuperClassExpr = null;

		mMaxFrameCount = 0;
		mMaxVariableCount = 0;

		mFuncDeclArgCount = 0;
		mFuncDeclUnnamedArgArrayBase = 0;
		mFuncDeclCollapseBase = -1;

		mFunctionRegisterCodePoint = 0;

		mPrevSourcePos = -1;
		mSourcePosArraySorted = false;
		mSourcePosArray = null;

		if(name != null && name.length() > 0 ) {
			mName = name;
		} else {
			mName = null;
		}
		mAsGlobalContextMode = false;
		mContextType = type;
		switch(mContextType) // decide variable reservation count with context type
		{
			case ContextType.TOP_LEVEL:			mVariableReserveCount = 2; break;
			case ContextType.FUNCTION:			mVariableReserveCount = 2; break;
			case ContextType.EXPR_FUNCTION: 	mVariableReserveCount = 2; break;
			case ContextType.PROPERTY:			mVariableReserveCount = 0; break;
			case ContextType.PROPERTY_SETTER:	mVariableReserveCount = 2; break;
			case ContextType.PROPERTY_GETTER:	mVariableReserveCount = 2; break;
			case ContextType.CLASS:				mVariableReserveCount = 2; break;
			case ContextType.SUPER_CLASS_GETTER:mVariableReserveCount = 2; break;
		}
		mBlock = block;
		mBlock.add( this );

		if( mContextType == ContextType.CLASS ) {
			// add class information to the class instance information
			if( mMaxFrameCount < 1 ) mMaxFrameCount = 1;

			int dp = putData(new Variant(mName));
			int lexPos = getLexPos();
			// const %1, name
			// addci %-1, %1
			// cl %1
			putCode(VM_CONST, lexPos);
			putCode(1);
			putCode(dp);
			putCode(VM_ADDCI);
			putCode(-1);
			putCode(1);
			putCode(VM_CL);
			putCode(1);

			// update FunctionRegisterCodePoint
			mFunctionRegisterCodePoint = mCodeArea.position(); // update FunctionRegisterCodePoint
		}
	}
	protected void finalizeObject() throws VariantException, TJSException {
		if( mPropSetter != null ) mPropSetter = null;
		if( mPropGetter != null ) mPropGetter = null;
		if( mSuperClassGetter != null ) mSuperClassGetter = null;
		if( mCodeArea != null ) { mCodeArea.clear(); mCodeArea = null; }
		if( mDataArea != null ) {
			mDataArea.clear();
			mDataArea = null;
		}
		mBlock.remove(this);

		if( mContextType!=ContextType.TOP_LEVEL && mBlock != null ) mBlock = null;

		mNamespace.clear();

		clearNodesToDelete();

		if( mSourcePosArray != null ) {
			mSourcePosArray.clear();
			mSourcePosArray = null;
		}
		super.finalizeObject();
	}
	public final String getName(){ return mName; }
	private int getLexPos() {
		return mBlock.getLexicalAnalyzer().getCurrentPosition();
	}
	public int getNodeToDeleteVectorCount() { return mNodeToDeleteVector.size(); }

	public void pushCurrentNode( ExprNode node ) {
		mCurrentNodeVector.add( node );
	}
	public ExprNode getCurrentNode() {
		if( mCurrentNodeVector.size() == 0 ) return null;
		return mCurrentNodeVector.get( mCurrentNodeVector.size()-1 );
	}
	public void popCurrentNode() {
		final int count = mCurrentNodeVector.size();
		if( count > 0 ) {
			mCurrentNodeVector.remove( count - 1 );
		}
	}
	private int putCode( int num ) { return putCode( num, -1 ); }
	private int putCode( int num, int pos ) {
		/*
		if( mCodeArea == null ) {
			ByteBuffer buff = ByteBuffer.allocateDirect(INC_SIZE_BYTE);
			buff.order( ByteOrder.nativeOrder() );
			mCodeArea = buff.asIntBuffer();
			mCodeArea.clear();
		}
		*/
		final int capacity = mCodeArea.capacity();
		if( mCodeArea.position() >= capacity ) {
			ByteBuffer buff = ByteBuffer.allocateDirect(mCodeArea.capacity()*4+INC_SIZE_BYTE);
			buff.order( ByteOrder.nativeOrder() );
			IntBuffer ibuff = buff.asIntBuffer();
			ibuff.clear();
			mCodeArea.flip();
			ibuff.put( mCodeArea );
			mCodeArea = null;
			mCodeArea = ibuff;
		}
		if( pos != -1 ) {
			if( mPrevSourcePos != pos ) {
				mPrevSourcePos = pos;
				mSourcePosArraySorted = false;
				if( mSourcePosArray == null ) {
					ByteBuffer buff = ByteBuffer.allocateDirect(INC_SIZE_LONG_BYTE);
					buff.order( ByteOrder.nativeOrder() );
					mSourcePosArray = buff.asLongBuffer();
					mSourcePosArray.clear();
				}
				final int longCapacity = mSourcePosArray.capacity();
				if( mSourcePosArray.position() >= longCapacity ) {
					ByteBuffer buff = ByteBuffer.allocateDirect(mSourcePosArray.capacity()*8+INC_SIZE_BYTE);
					buff.order( ByteOrder.nativeOrder() );
					LongBuffer lbuff = buff.asLongBuffer();
					lbuff.clear();
					mSourcePosArray.flip();
					lbuff.put( mSourcePosArray );
					mSourcePosArray = null;
					mSourcePosArray = lbuff;
				}
				mSourcePosArray.put( ((long)mCodeArea.position() << 32) | (long)pos );
			}
		}
		int ret = mCodeArea.position();
		mCodeArea.put(num);
		return ret;
	}
	private int putData( final Variant val ) throws VariantException {
		// 直近の20個の中で同じものがあるか調べる
		final int size = mDataArea.size();
		int count = size > 20 ? 20 : size;
		final int offset = size  - 1;
		for( int i = 0; i < count; i++ ) {
			int pos = offset - i;
			if( mDataArea.get( pos ).discernCompareStrictReal(val) ) {
				return pos;
			}
		}
		Variant v;
		if( val.isString() ) {
			v = new Variant( TJS.mapGlobalStringMap( val.asString() ) );
		} else {
			v = new Variant ( val );
		}
		mDataArea.add( v );
		return mDataArea.size() - 1;
	}

	private void clearLocalVariable(int vc, int pvc) {
		// clear local variable registers from top-1 to bottom
/*
 * 何もしない様子
		if(top - bottom >= 3)
		{
			PutCode(VM_CCL); // successive clear instruction
			PutCode(TJS_TO_VM_REG_ADDR(-(top-1)-VariableReserveCount-1));
			PutCode(top-bottom);
		}
		else
		{
			for(tjs_int i = bottom; i<top; i++)
			{
				PutCode(VM_CL);
				PutCode(TJS_TO_VM_REG_ADDR(-i-VariableReserveCount-1));
			}
		}
*/
	}
	public void addLocalVariable( final String name ) throws VariantException { addLocalVariable( name, 0 ); }
	public void addLocalVariable( final String name, int init ) throws VariantException {
		int base = mContextType == ContextType.CLASS ? 2 : 1;
		int lexPos = getLexPos();
		if( mNamespace.getLevel() >= base ) {
			mNamespace.add(name);
			if( init != 0 ) {
				int n = mNamespace.find(name);
				putCode( VM_CP, lexPos );
				putCode( -n-mVariableReserveCount-1, lexPos );
				putCode( init, lexPos );
			} else {
				int n = mNamespace.find(name);
				putCode( VM_CL, lexPos );
				putCode( -n-mVariableReserveCount-1, lexPos );
			}
		} else {
			int dp = putData(new Variant(name));
			putCode( VM_SPDS, lexPos );
			putCode( -1, lexPos );
			putCode( dp, lexPos );
			putCode( init, lexPos );
		}
	}
	public void initLocalVariable( final String name, ExprNode node ) throws VariantException, CompileException  {
		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode( fr, node, RT_NEEDED, 0, new SubParam() );
		addLocalVariable(name,resaddr);
		clearFrame(fr);
	}
	public void initLocalFunction( final String name, int data ) throws VariantException {
		// create a local function variable pointer by data ( in DataArea ),
		// named "name".
		int fr = mFrameBase;
		int pos = getLexPos();
		putCode(VM_CONST, pos );
		putCode( fr, pos );
		putCode( data);
		fr++;
		addLocalVariable( name, fr-1 );
		clearFrame(fr);
	}
	public void createExprCode( ExprNode node ) throws VariantException, CompileException {
		// create code of node
		IntWrapper fr = new IntWrapper(mFrameBase);
		genNodeCode(fr, node, 0, 0, new SubParam());
		clearFrame(fr);
	}
	public void enterWhileCode( boolean doWhile ) {
		// enter to "while"
		// ( do_while = true indicates do-while syntax )
		mNestVector.add( new NestData() );
		mNestVector.lastElement().Type = doWhile ? ntDoWhile : ntWhile;
		mNestVector.lastElement().LoopStartIP = mCodeArea.position();
	}
	public void createWhileExprCode( ExprNode node, boolean doWhile ) throws VariantException, CompileException {
		// process the condition expression "node"
		if( doWhile ) {
			doContinuePatch( mNestVector.lastElement() );
		}

		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode( fr, node, RT_NEEDED|RT_CFLAG, 0, new SubParam() );
		int nodepos = (node != null ? node.getPosition() : -1);
		boolean inv = false;
		if( !(resaddr == GNC_CFLAG || resaddr == GNC_CFLAG_I ) ) {
			putCode( VM_TT, nodepos );
			putCode( resaddr, nodepos );
		} else {
			if(resaddr == GNC_CFLAG_I) inv = true;
		}
		clearFrame(fr);

		if( !doWhile ) {
			mNestVector.lastElement().ExitPatchVector.add(mCodeArea.position());
			addJumpList();
			putCode(inv?VM_JF:VM_JNF, nodepos);
			putCode(0, nodepos);
		} else {
			int jmp_ip = mCodeArea.position();
			addJumpList();
			putCode(inv?VM_JNF:VM_JF, nodepos);
			putCode(mNestVector.lastElement().LoopStartIP - jmp_ip, nodepos);
		}
	}
	public void exitWhileCode( boolean doWhile ) throws CompileException {
		// exit from "while"
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( doWhile ) {
			if( mNestVector.lastElement().Type != ntDoWhile) {
				mBlock.error(Error.SyntaxError);
				return;
			}
		} else {
			if( mNestVector.lastElement().Type != ntWhile ) {
				mBlock.error(Error.SyntaxError);
				return;
			}
		}

		if( !doWhile ) {
			int jmp_ip = mCodeArea.position();
			addJumpList();
			int pos = getLexPos();
			putCode(VM_JMP, pos );
			putCode( mNestVector.lastElement().LoopStartIP - jmp_ip, pos );
		}
		doNestTopExitPatch();
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void enterIfCode() {
		// enter to "if"
		mNestVector.add( new NestData() );
		mNestVector.lastElement().Type = ntIf;
	}
	public void crateIfExprCode( ExprNode node ) throws VariantException, CompileException {
		// process condition expression "node"
		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode(fr, node, RT_NEEDED|RT_CFLAG, 0, new SubParam());
		int nodepos = (node != null ? node.getPosition() : -1);
		boolean inv = false;
		if(!(resaddr == GNC_CFLAG || resaddr == GNC_CFLAG_I)) {
			putCode(VM_TT, nodepos );
			putCode(resaddr, nodepos );
		} else {
			if(resaddr == GNC_CFLAG_I) inv = true;
		}
		clearFrame(fr);
		mNestVector.lastElement().Patch1 = mCodeArea.position();
		addJumpList();
		putCode(inv?VM_JF:VM_JNF, nodepos );
		putCode(0, nodepos );
	}
	public void exitIfCode() throws CompileException {
		// exit from if
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( mNestVector.lastElement().Type != ntIf) {
			mBlock.error(Error.SyntaxError);
			return;
		}

		mCodeArea.put( mNestVector.lastElement().Patch1 + 1, mCodeArea.position() - mNestVector.lastElement().Patch1 );
		mPrevIfExitPatch = mNestVector.lastElement().Patch1;
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void enterElseCode() {
		// enter to "else".
		// before is "if", is clear from syntax definition.
		mNestVector.add(new NestData());
		mNestVector.lastElement().Type = ntElse;
		mNestVector.lastElement().Patch2 = mCodeArea.position();
		addJumpList();
		int pos = getLexPos();
		putCode(VM_JMP, pos);
		putCode(0, pos);
		mCodeArea.put( mPrevIfExitPatch + 1, mCodeArea.position() - mPrevIfExitPatch );
	}
	public void exitElseCode() throws CompileException {
		// exit from else
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( mNestVector.lastElement().Type != ntElse ) {
			mBlock.error(Error.SyntaxError);
			return;
		}

		mCodeArea.put( mNestVector.lastElement().Patch2 + 1, mCodeArea.position() - mNestVector.lastElement().Patch2 );
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void enterForCode(boolean varcreate) {
		// enter to "for".
		// ( varcreate = true, indicates that the variable is to be created in the
		//	first clause )
		mNestVector.add( new NestData() );
		mNestVector.lastElement().Type = ntFor;
		if(varcreate) enterBlock(); // create a scope
		mNestVector.lastElement().VariableCreated = varcreate;
	}
	public void createForExprCode( ExprNode node ) throws VariantException, CompileException {
		// process the "for"'s second clause; a condition expression
		mNestVector.lastElement().LoopStartIP = mCodeArea.position();
		if( node != null ) {
			int nodepos = node.getPosition();
			IntWrapper fr = new IntWrapper( mFrameBase );
			int resaddr = genNodeCode( fr, node, RT_NEEDED|RT_CFLAG, 0, new SubParam() );
			boolean inv = false;
			if(!(resaddr == GNC_CFLAG || resaddr == GNC_CFLAG_I) ) {
				putCode(VM_TT, nodepos );
				putCode(resaddr, nodepos );
			} else {
				if(resaddr == GNC_CFLAG_I) inv = true;
			}
			clearFrame(fr);
			mNestVector.lastElement().ExitPatchVector.add(mCodeArea.position());
			addJumpList();
			putCode(inv?VM_JF:VM_JNF, nodepos);
			putCode( 0, nodepos );
		}
	}
	public void setForThirdExprCode( ExprNode node ) {
		// process the "for"'s third clause; a post-loop expression
		mNestVector.lastElement().PostLoopExpr = node;
	}
	public void exitForCode() throws CompileException, VariantException {
		// exit from "for"
		int nestsize = mNestVector.size();
		if(nestsize == 0) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if(mNestVector.lastElement().Type != ntFor && mNestVector.lastElement().Type != ntBlock) {
			mBlock.error(Error.SyntaxError);
			return;
		}

		if( mNestVector.lastElement().Type == ntFor)
			doContinuePatch(mNestVector.lastElement());
		if(nestsize >= 2 && mNestVector.get(nestsize-2).Type == ntFor)
			doContinuePatch( mNestVector.get(nestsize-2) );

		if( mNestVector.lastElement().PostLoopExpr != null ) {
			IntWrapper fr = new IntWrapper(mFrameBase);
			genNodeCode(fr, mNestVector.lastElement().PostLoopExpr, 0, 0, new SubParam());
			clearFrame(fr);
		}
		int jmp_ip = mCodeArea.position();
		addJumpList();
		int lexpos = getLexPos();
		putCode(VM_JMP, lexpos );
		putCode( mNestVector.lastElement().LoopStartIP - jmp_ip, lexpos );
		doNestTopExitPatch();
		if( mNestVector.lastElement().VariableCreated ) exitBlock();
		doNestTopExitPatch();
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void enterSwitchCode( ExprNode node ) throws VariantException, CompileException {
		// enter to "switch"
		// "node" indicates a reference expression
		mNestVector.add(new NestData());
		mNestVector.lastElement().Type = ntSwitch;
		mNestVector.lastElement().Patch1 = -1;
		mNestVector.lastElement().Patch2 = -1;
		//mNestVector.lastElement().IsFirstCase = true; // IsFirstCase と VariableCreated は同一に扱う
		mNestVector.lastElement().VariableCreated = true;

		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam());

		if( mFrameBase != resaddr ) {
			int nodepos = (node != null ? node.getPosition() : -1);
			putCode(VM_CP, nodepos);
			putCode(mFrameBase, nodepos ); // FrameBase points the reference value
			putCode(resaddr, nodepos );
		}

		mNestVector.lastElement().RefRegister = mFrameBase;

		if(fr.value-1 > mMaxFrameCount) mMaxFrameCount = fr.value-1;

		mFrameBase++; // increment FrameBase
		if(mFrameBase-1 > mMaxFrameCount) mMaxFrameCount = mFrameBase-1;

		clearFrame(fr);

		enterBlock();
	}
	public void exitSwitchCode() throws CompileException {
		// exit from switch
		exitBlock();
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( mNestVector.lastElement().Type != ntSwitch ) {
			mBlock.error(Error.SyntaxError);
			return;
		}

		int lexpos = getLexPos();
		int patch3 = 0;
		//if( !mNestVector.lastElement().IsFirstCase ) // IsFirstCase と VariableCreated は同一に扱う
		if( !mNestVector.lastElement().VariableCreated ) {
			patch3 = mCodeArea.position();
			addJumpList();
			putCode( VM_JMP, lexpos );
			putCode( 0, lexpos );
		}


		if( mNestVector.lastElement().Patch1 != -1 ) {
			mCodeArea.put( mNestVector.lastElement().Patch1 +1, mCodeArea.position() - mNestVector.lastElement().Patch1 );
		}

		if( mNestVector.lastElement().Patch2 != -1 ) {
			addJumpList();
			int jmp_start = mCodeArea.position();
			putCode( VM_JMP, lexpos);
			putCode( mNestVector.lastElement().Patch2 - jmp_start, lexpos);
		}

		//if( !mNestVector.lastElement().IsFirstCase ) {
		if( !mNestVector.lastElement().VariableCreated ) {
			mCodeArea.put( patch3 +1, mCodeArea.position()- patch3 );
		}

		doNestTopExitPatch();
		mFrameBase--;
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void processCaseCode( ExprNode node ) throws VariantException, CompileException {
		// process "case expression :".
		// process "default :" if node == NULL.
		int nestsize = mNestVector.size();
		if( nestsize < 3 ) {
			mBlock.error(Error.MisplacedCase);
			return;
		}
		if( mNestVector.get( nestsize-1 ).Type != ntBlock ||
			mNestVector.get( nestsize-2 ).Type != ntBlock ||
			mNestVector.get( nestsize-3 ).Type != ntSwitch ) {
			// the stack layout must be ( from top )
			// ntBlock, ntBlock, ntSwitch
			mBlock.error(Error.MisplacedCase);
			return;
		}

		NestData data = mNestVector.get(mNestVector.size()-3);
		int patch3 = 0;
		//if( !data.IsFirstCase ) { // IsFirstCase と VariableCreated は同一に扱う
		if( !data.VariableCreated ) {
			patch3 = mCodeArea.position();
			addJumpList();
			int nodepos = (node != null ? node.getPosition() : -1);
			putCode(VM_JMP, nodepos);
			putCode(0, nodepos);
		}

		exitBlock();
		if( data.Patch1 != -1 ) {
			mCodeArea.put( data.Patch1 +1, mCodeArea.position() - data.Patch1 );
		}

		if( node != null ) {
			IntWrapper fr = new IntWrapper(mFrameBase);
			int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam());
			int nodepos = (node != null ? node.getPosition() : -1);
			putCode( VM_CEQ, nodepos);
			putCode( data.RefRegister, nodepos);
				// compare to reference value with normal comparison
			putCode( resaddr, nodepos);
			clearFrame(fr);
			data.Patch1 = mCodeArea.position();
			addJumpList();
			putCode(VM_JNF, nodepos);
			putCode(0, nodepos);
		} else {
			data.Patch1 = mCodeArea.position();
			addJumpList();
			int nodepos = (node != null ? node.getPosition() : -1);
			putCode(VM_JMP, nodepos);
			putCode(0, nodepos);

			data.Patch2 = mCodeArea.position(); // Patch2 = "default:"'s position
		}

		//if( !data.IsFirstCase ) {
		if( !data.VariableCreated ) {
			mCodeArea.put( patch3 +1, mCodeArea.position() - patch3 );
		}
		//data.IsFirstCase = false;
		data.VariableCreated = false;

		enterBlock();
	}
	public void enterWithCode( ExprNode node ) throws VariantException, CompileException {
		// enter to "with"
		// "node" indicates a reference expression

		// this method and ExitWithCode are very similar to switch's code.
		// (those are more simple than that...)

		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam());

		int nodepos = (node != null ? node.getPosition() : -1);
		if( mFrameBase != resaddr ) {
			// bring the reference variable to frame base top
			putCode(VM_CP, nodepos);
			putCode( mFrameBase, nodepos); // FrameBase points the reference value
			putCode( resaddr, nodepos);
		}

		mNestVector.add(new NestData());
		mNestVector.lastElement().Type = ntWith;

		mNestVector.lastElement().RefRegister = mFrameBase;

		if( fr.value-1 > mMaxFrameCount) mMaxFrameCount = fr.value-1;

		mFrameBase ++; // increment FrameBase
		if(mFrameBase-1 > mMaxFrameCount) mMaxFrameCount = mFrameBase-1;

		clearFrame(fr);

		enterBlock();
	}
	public void exitWidthCode() throws CompileException {
		// exit from switch
		exitBlock();
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( mNestVector.lastElement().Type != ntWith ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		mFrameBase--;
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void doBreak() throws CompileException {
		// process "break".

		// search in NestVector backwards
		int vc = mNamespace.getCount();
		int pvc = vc;

		int lexpos = getLexPos();
		int i = mNestVector.size() -1;
		for( ; i>=0; i-- ) {
			NestData data = mNestVector.get(i);
			if( data.Type == ntSwitch ||
				data.Type == ntWhile || data.Type == ntDoWhile ||
				data.Type == ntFor ) {
				// "break" can apply on this syntax
				clearLocalVariable(vc, pvc); // clear local variables
				data.ExitPatchVector.add( mCodeArea.position() );
				addJumpList();
				putCode(VM_JMP, lexpos);
				putCode(0, lexpos); // later patches here
				return;
			} else if(data.Type == ntBlock) {
				pvc = data.VariableCount;
			} else if(data.Type == ntTry) {
				putCode(VM_EXTRY);
			} else if(data.Type == ntSwitch || data.Type == ntWith) {
				// clear reference register of "switch" or "with" syntax
			}
		}

		mBlock.error( Error.MisplacedBreakContinue );
	}
	public void doContinue() throws CompileException {
		// process "continue".

		// generate code that jumps before '}' ( the end of the loop ).
		// for "while" loop, the jump code immediately jumps to the condition check code.

		// search in NestVector backwards
		int vc = mNamespace.getCount();
		int pvc = vc;
		int i = mNestVector.size() - 1;
		int lexpos = getLexPos();
		for( ; i>=0; i-- ) {
			NestData data = mNestVector.get(i);
			if( data.Type == ntWhile ) {
				// for "while" loop
				clearLocalVariable(vc, pvc); // clear local variables
				int jmpstart = mCodeArea.position();
				addJumpList();
				putCode(VM_JMP, lexpos);
				putCode(data.LoopStartIP - jmpstart, lexpos);
				return;
			} else if( data.Type == ntDoWhile || data.Type == ntFor ) {
				// "do-while" or "for" loop needs forward jump
				clearLocalVariable(vc, pvc); // clears local variables
				data.ContinuePatchVector.add( mCodeArea.position() );
				addJumpList();
				putCode(VM_JMP, lexpos);
				putCode(0, lexpos); // later patch this
				return;
			} else if( data.Type == ntBlock ) {
				// does not count variables which created at for loop's
				// first clause
				if( i < 1 || mNestVector.get( i-1 ).Type != ntFor || !mNestVector.get(i).VariableCreated )
					pvc = data.VariableCount;
			} else if(data.Type == ntTry) {
				putCode(VM_EXTRY, lexpos);
			} else if(data.Type == ntSwitch || data.Type == ntWith) {
				// clear reference register of "switch" or "with" syntax
			}
		}
		mBlock.error( Error.MisplacedBreakContinue );
	}
	public void doDebugger() {
		// process "debugger" statement.
		putCode(VM_DEBUGGER, getLexPos() );
	}
	public void returnFromFunc( ExprNode node ) throws VariantException, CompileException {
		// precess "return"
		// note: the "return" positioned in global immediately returns without
		// execution of the remainder code.

		int nodepos = (node != null ? node.getPosition() : -1);
		if( node == null ) {
			// no return value
			putCode( VM_SRV, nodepos );
			putCode( 0, nodepos );  // returns register #0 = void
		} else {
			// generates return expression
			IntWrapper fr = new IntWrapper(mFrameBase);
			int resaddr = genNodeCode( fr, node, RT_NEEDED, 0, new SubParam() );
			putCode(VM_SRV, nodepos);
			putCode( resaddr, nodepos);
			clearFrame(fr);
		}

		// clear the frame
		int org_framebase = mFrameBase;
		clearFrame(mFrameBase, 1);
		mFrameBase = org_framebase;

		// clear local variables
		clearLocalVariable(mNamespace.getCount(), 0);

		int lexpos = getLexPos();
		// check try block
		int i = mNestVector.size() -1;
		for( ; i>=0; i-- ) {
			NestData data = mNestVector.get(i);
			if(data.Type == ntTry) {
				putCode(VM_EXTRY, lexpos); // exit from try-protected block
			}
		}
		putCode(VM_RET, lexpos);
	}
	public void enterTryCode() {
		// enter to "try"
		mNestVector.add(new NestData());
		mNestVector.lastElement().Type = ntTry;
		mNestVector.lastElement().VariableCreated = false;

		int lexpos = getLexPos();
		mNestVector.lastElement().Patch1 = mCodeArea.position();
		addJumpList();
		putCode(VM_ENTRY, lexpos);
		putCode(0, lexpos);
		putCode( mFrameBase, lexpos); // an exception object will be held here

		if( mFrameBase > mMaxFrameCount ) mMaxFrameCount = mFrameBase;
	}
	public void enterCatchCode( final String name ) throws VariantException {
		// enter to "catch"
		int lexpos = getLexPos();
		putCode(VM_EXTRY, lexpos);
		mNestVector.lastElement().Patch2 = mCodeArea.position();
		addJumpList();
		putCode(VM_JMP, lexpos);
		putCode(0, lexpos);

		mCodeArea.put( mNestVector.lastElement().Patch1 + 1, mCodeArea.position() - mNestVector.lastElement().Patch1 );

		// clear local variables
		clearLocalVariable(mNamespace.getMaxCount(), mNamespace.getCount());

		// clear frame
		int fr = mMaxFrameCount + 1;
		int base = name != null ? mFrameBase+1 : mFrameBase;
		clearFrame(fr, base);

		// change nest type to ntCatch
		mNestVector.lastElement().Type = ntCatch;

		// create variable if the catch clause has a receiver variable name
		if( name != null ) {
			mNestVector.lastElement().VariableCreated = true;
			enterBlock();
			addLocalVariable(name, mFrameBase);
				// cleate a variable that receives the exception object
		}
	}
	public void exitTryCode() throws CompileException {
		// exit from "try"
		if( mNestVector.size() >= 2 ) {
			if( mNestVector.get(mNestVector.size()-2).Type == ntCatch ) {
				if( mNestVector.get(mNestVector.size()-2).VariableCreated ) {
					exitBlock();
				}
			}
		}
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( mNestVector.lastElement().Type != ntCatch ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		int p2addr = mNestVector.lastElement().Patch2;
		mCodeArea.put( p2addr + 1, mCodeArea.position() - p2addr );
		mNestVector.remove( mNestVector.size()-1 );
	}
	public void processThrowCode( ExprNode node ) throws VariantException, CompileException {
		// process "throw".
		// node = expressoin to throw
		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam() );
		int nodepos = (node != null ? node.getPosition() : -1);
		putCode(VM_THROW, nodepos);
		putCode(resaddr, nodepos);
		if(fr.value-1 > mMaxFrameCount) mMaxFrameCount = fr.value-1;
	}
	public void createExtendsExprCode( ExprNode node, boolean hold ) throws VariantException, CompileException {
		// process class extender
		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam() );

		int nodepos = (node != null ? node.getPosition() : -1);
		putCode(VM_CHGTHIS, nodepos);
		putCode(resaddr, nodepos);
		putCode(-1, nodepos);

		putCode(VM_CALL, nodepos);
		putCode(0, nodepos);
		putCode(resaddr, nodepos);
		putCode(0, nodepos);

		if( hold ) {
			mSuperClassExpr = node;
		}
		mFunctionRegisterCodePoint = mCodeArea.position(); // update FunctionRegisterCodePoint

		// create a Super Class Proxy context
		if( mSuperClassGetter == null ) {
			mSuperClassGetter = new InterCodeContext(this, mName, mBlock, ContextType.SUPER_CLASS_GETTER );
		}
		mSuperClassGetter.createExtendsExprProxyCode(node);
	}
	public void createExtendsExprProxyCode( ExprNode node ) throws VariantException, CompileException {
		// create super class proxy to retrieve super class
		mSuperClassGetterPointer.add(mCodeArea.position());

		IntWrapper fr = new IntWrapper(mFrameBase);
		int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam() );

		putCode(VM_SRV);
		putCode(resaddr);
		clearFrame(fr);

		putCode(VM_RET);

		int nodepos = (node != null ? node.getPosition() : -1);
		putCode(VM_NOP, nodepos);
	}
	public void enterBlock() {
		// enter to block
		mNamespace.push();
		int varcount = mNamespace.getCount();
		mNestVector.add(new NestData());
		mNestVector.lastElement().Type = ntBlock;
		mNestVector.lastElement().VariableCount = varcount;
	}
	public void exitBlock() throws CompileException {
		// exit from block
		if( mNestVector.size() == 0 ) {
			mBlock.error(Error.SyntaxError);
			return;
		}
		if( mNestVector.lastElement().Type != ntBlock ) {
			mBlock.error(Error.SyntaxError);
			return;
		}

		mNestVector.remove( mNestVector.size()-1 );
		int prevcount = mNamespace.getCount();
		mNamespace.pop();
		int curcount = mNamespace.getCount();
		clearLocalVariable(prevcount, curcount);
	}
	public void generateFuncCallArgCode() {
		int lexpos = getLexPos();
		if( mFuncArgStack.peek().IsOmit ) {
			putCode(-1, lexpos); // omit (...) is specified
		} else if( mFuncArgStack.peek().HasExpand ) {
			putCode(-2, lexpos); // arguments have argument expanding node
			Vector<FuncArgItem> vec = mFuncArgStack.peek().ArgVector;
			putCode(vec.size(), lexpos); // count of the arguments
			for(int i=0; i<vec.size(); i++) {
				putCode(vec.get(i).Type, lexpos);
				putCode(vec.get(i).Register, lexpos);
			}
		} else {
			Vector<FuncArgItem> vec = mFuncArgStack.peek().ArgVector;
			putCode(vec.size(), lexpos); // count of arguments
			for( int i=0; i<vec.size(); i++)
				putCode( vec.get(i).Register, lexpos);
		}
	}
	public void addFunctionDeclArg( final String varname, ExprNode node ) throws VariantException, CompileException {
		// process the function argument of declaration
		// varname = argument name
		// init = initial expression

		mNamespace.add(varname);

		if( node != null ) {
			int nodepos = (node != null ? node.getPosition() : -1);
			putCode(VM_CDEQ, nodepos);
			putCode(-3 - mFuncDeclArgCount, nodepos);
			putCode(0, nodepos);
			int jmp_ip = mCodeArea.position();
			addJumpList();
			putCode(VM_JNF, nodepos);
			putCode(0, nodepos);

			IntWrapper fr = new IntWrapper(mFrameBase);
			int resaddr = genNodeCode(fr, node, RT_NEEDED, 0, new SubParam());
			putCode(VM_CP, nodepos);
			putCode(-3 - mFuncDeclArgCount, nodepos);
			putCode(resaddr, nodepos);
			clearFrame(fr);

			mCodeArea.put( jmp_ip+1, mCodeArea.position()- jmp_ip );

		}
		mFuncDeclArgCount++;
	}
	public void addFunctionDeclArgCollapse( final String varname ) {
		// process the function "collapse" argument of declaration.
		// collapse argument is available to receive arguments in array object form.
		if( varname == null ) {
			// receive arguments in unnamed array
			mFuncDeclUnnamedArgArrayBase = mFuncDeclArgCount;
		} else {
			// receive arguments in named array
			mFuncDeclCollapseBase = mFuncDeclArgCount;
			mNamespace.add(varname);
		}
	}
	public void setPropertyDeclArg( final String varname ) {
		// process the setter argument
		mNamespace.add(varname);
		mFuncDeclArgCount = 1;
	}
	private void doNestTopExitPatch() {
		// process the ExitPatchList which must be in the top of NextVector
		Vector<Integer> vector = mNestVector.lastElement().ExitPatchVector;
		final int count = vector.size();
		final int codeSize = mCodeArea.position();
		for( int i = 0; i < count; i++ ) {
			int val = vector.get(i).intValue();
			mCodeArea.put( val+1, codeSize - val );
		}
	}
	private void doContinuePatch(NestData nestdata) {
		// process the ContinuePatchList which must be in the top of NextVector
		Vector<Integer> vector = nestdata.ContinuePatchVector;
		final int count = vector.size();
		final int codeSize = mCodeArea.position();
		for( int i = 0; i < count; i++ ) {
			int val = vector.get(i).intValue();
			mCodeArea.put( val+1, codeSize - val );
		}
	}

	public ExprNode makeConstValNode( Variant val ) {
		ExprNode node = new ExprNode();
		mNodeToDeleteVector.add( node );
		node.setOpecode( Token.T_CONSTVAL );
		node.setValue( val );
		node.setPosition( getLexPos() );
		return node;
	}
	public static void characterCodeFrom( Variant val ) throws VariantException {
		char ch[] = new char[1];
		ch[0] = (char) val.asInteger();
		val.set( new String(ch) );
	}
	public static void characterCodeOf( Variant val ) throws VariantException {
		String str = val.asString();
		if( str != null ) {
			int v = str.codePointAt(0);
			val.set( v );
		} else {
			val.set( 0 );
		}
	}

	public ExprNode makeNP0( int opecode ) {
		ExprNode node = new ExprNode();
		mNodeToDeleteVector.add( node );
		node.setOpecode(opecode);
		node.setPosition( getLexPos() );
		return node;
	}
	public ExprNode makeNP1( int opecode, ExprNode node1 ) throws VariantException {
		// 定数の最適化
		if( node1 != null && node1.getOpecode() == Token.T_CONSTVAL ) {
			ExprNode ret = null;
			switch( opecode ) {
			case Token.T_EXCRAMATION:
				ret = makeConstValNode( node1.getValue().getNotValue() );
				break;
			case Token.T_TILDE:
				ret = makeConstValNode( node1.getValue().getBitNotValue() );
				break;
			case Token.T_SHARP: {
				Variant val = new Variant(node1.getValue() );
				characterCodeOf(val);
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_DOLLAR: {
				Variant val = new Variant(node1.getValue() );
				characterCodeFrom(val);
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_UPLUS: {
				Variant val = new Variant(node1.getValue() );
				val.toNumber();
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_UMINUS: {
				Variant val = new Variant(node1.getValue() );
				val.changeSign();
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_INT: {
				Variant val = new Variant(node1.getValue() );
				val.toInteger();
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_REAL: {
				Variant val = new Variant(node1.getValue() );
				val.toReal();
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_STRING: {
				Variant val = new Variant(node1.getValue() );
				val.toString();
				ret = makeConstValNode( val );
				break;
			}
			case Token.T_OCTET: {
				Variant val = new Variant(node1.getValue() );
				val.toOctet();
				ret = makeConstValNode( val );
				break;
			}
			} // swtich
			if( ret != null ) {
				node1.clear();
				return ret;
			}
		}
		ExprNode node = new ExprNode();
		mNodeToDeleteVector.add( node );
		node.setOpecode(opecode);
		node.setPosition( getLexPos() );
		node.add( node1 );
		return node;
	}
	public ExprNode makeNP2( int opecode, ExprNode node1, ExprNode node2 ) throws VariantException {
		// 定数の最適化
		if( node1 != null && node1.getOpecode() == Token.T_CONSTVAL && node2 != null && node2.getOpecode() == Token.T_CONSTVAL ) {
			switch( opecode ) {
			case Token.T_COMMA:
				return makeConstValNode( node2.getValue() );
			case Token.T_LOGICALOR:
				return makeConstValNode( node1.getValue().logicOr( node2.getValue() ) );
			case Token.T_LOGICALAND:
				return makeConstValNode( node1.getValue().logicAnd( node2.getValue() ) );
			case Token.T_VERTLINE:
				return makeConstValNode( node1.getValue().bitOr( node2.getValue() ) );
			case Token.T_CHEVRON:
				return makeConstValNode( node1.getValue().bitXor( node2.getValue() ) );
			case Token.T_AMPERSAND:
				return makeConstValNode( node1.getValue().bitAnd( node2.getValue() ) );
			case Token.T_NOTEQUAL:
				return makeConstValNode( node1.getValue().notEqual( node2.getValue() ) );
			case Token.T_EQUALEQUAL:
				return makeConstValNode( node1.getValue().equalEqual( node2.getValue() ) );
			case Token.T_DISCNOTEQUAL:
				return makeConstValNode( node1.getValue().discNotEqual( node2.getValue() ) );
			case Token.T_DISCEQUAL:
				return makeConstValNode( node1.getValue().discernCompare( node2.getValue() ) );
			case Token.T_LT:
				return makeConstValNode( node1.getValue().lt( node2.getValue() ) );
			case Token.T_GT:
				return makeConstValNode( node1.getValue().gt( node2.getValue() ) );
			case Token.T_LTOREQUAL:
				return makeConstValNode( node1.getValue().ltOrEqual( node2.getValue() ) );
			case Token.T_GTOREQUAL:
				return makeConstValNode( node1.getValue().gtOrEqual( node2.getValue() ) );
			case Token.T_RARITHSHIFT:
				return makeConstValNode( node1.getValue().rightShift( node2.getValue() ) );
			case Token.T_LARITHSHIFT:
				return makeConstValNode( node1.getValue().leftShift( node2.getValue() ) );
			case Token.T_RBITSHIFT:
				return makeConstValNode( node1.getValue().rightBitShift( node2.getValue() ) );
			case Token.T_PLUS:
				return makeConstValNode( node1.getValue().add( node2.getValue() ) );
			case Token.T_MINUS:
				return makeConstValNode( node1.getValue().subtract( node2.getValue() ) );
			case Token.T_PERCENT:
				return makeConstValNode( node1.getValue().residue( node2.getValue() ) );
			case Token.T_SLASH:
				return makeConstValNode( node1.getValue().divide( node2.getValue() ) );
			case Token.T_BACKSLASH:
				return makeConstValNode( node1.getValue().idiv( node2.getValue() ) );
			case Token.T_ASTERISK:
				return makeConstValNode( node1.getValue().multiply( node2.getValue() ) );
			}
		}
		ExprNode node = new ExprNode();
		mNodeToDeleteVector.add( node );
		node.setOpecode(opecode);
		node.setPosition( getLexPos() );
		node.add( node1 );
		node.add( node2 );
		return node;
	}
	public ExprNode makeNP3( int opecode, ExprNode node1, ExprNode node2, ExprNode node3 ) {
		// 三項演算子の最適化とかはしていない？
		ExprNode node = new ExprNode();
		mNodeToDeleteVector.add( node );
		node.setOpecode(opecode);
		node.setPosition( getLexPos() );
		node.add( node1 );
		node.add( node2 );
		node.add( node3 );
		return node;
	}
	private int clearFrame( IntWrapper frame ) { return clearFrame( frame, -1); }
	private int clearFrame( IntWrapper frame, int base ) {
		if( base == -1 ) base = mFrameBase;
		if( (frame.value-1) > mMaxFrameCount ) mMaxFrameCount = frame.value - 1;
		if( (frame.value-base) >= 3 ) {
			frame.value = base;
		} else {
			/*
			while( frame > base ) { frame--; }
			*/
			if( frame.value > base ) frame.value = base;
		}
		return frame.value;
	}
	private int clearFrame( int frame ) { return clearFrame( frame, -1); }
	private int clearFrame( int frame, int base ) {
		if( base == -1 ) base = mFrameBase;
		if( (frame-1) > mMaxFrameCount ) mMaxFrameCount = frame - 1;
		if( (frame-base) >= 3 ) {
			frame = base;
		} else {
			if( frame > base ) frame = base;
		}
		return frame;
	}
	private int genNodeCode( IntWrapper frame, ExprNode node, int restype, int reqresaddr, SubParam param ) throws VariantException, CompileException {
		if( node == null ) return 0;

		int resaddr;
		int node_pos = ( node != null ? node.getPosition() : -1 );
		switch( node.getOpecode() ) {
		case Token.T_CONSTVAL:	// constant value
		{
			if( param.mSubType != stNone ) mBlock.error(Error.CannotModifyLHS );
			if( (restype&RT_NEEDED) == 0 ) return 0;
			int dp = putData( node.getValue() );
			putCode( VM_CONST, node_pos );
			putCode( frame.value, node_pos );
			putCode( dp, node_pos );
			int ret = frame.value;
			frame.value++;
			return ret;
		}
		case Token.T_IF:	// 'if'
		{
			if( (restype&RT_NEEDED) != 0 ) mBlock.error( Error.CannotGetResult );
			int resaddr1 = genNodeCode( frame, node.getNode(1), RT_NEEDED|RT_CFLAG, 0, new SubParam() );
			boolean inv = false;
			if( !(resaddr1==GNC_CFLAG||resaddr1==GNC_CFLAG_I) ) {
				putCode( VM_TT, node_pos );
				putCode( resaddr1, node_pos );
			} else {
				if( resaddr1 == GNC_CFLAG_I ) inv = true;
			}
			int addr = mCodeArea.position();
			addJumpList();
			putCode( inv ? VM_JF : VM_JNF, node_pos );
			putCode( 0, node_pos ); // *
			genNodeCode( frame, node.getNode(0), 0, 0, param );
			mCodeArea.put(addr+1, mCodeArea.position()-addr ); // patch "*"
			return 0;
		}
		case Token.T_INCONTEXTOF:	// 'incontextof'
		{
			if( (restype&RT_NEEDED) == 0 ) return 0;
			int resaddr1, resaddr2;
			resaddr1 = genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, param );
			resaddr2 = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0 , new SubParam() );
			if( resaddr1 <= 0 ) {
				putCode( VM_CP, node_pos );
				putCode( frame.value, node_pos );
				putCode( resaddr1, node_pos );
				resaddr1 = frame.value;
				frame.value++;
			}
			putCode( VM_CHGTHIS, node_pos );
			putCode( resaddr1, node_pos );
			putCode( resaddr2, node_pos );
			return resaddr1;
		}
		case Token.T_COMMA:	// ','
			genNodeCode( frame, node.getNode(0),0,0,new SubParam() );
			return genNodeCode( frame, node.getNode(1), restype, reqresaddr, param );

		case Token.T_SWAP:	// '<->'
		{
			if( (restype & RT_NEEDED) != 0 ) mBlock.error( Error.CannotGetResult );
			if( param.mSubType != 0 ) mBlock.error( Error.CannotModifyLHS );
			int resaddr1 = genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, new SubParam() );
			if( resaddr1 <= 0 ) {
				putCode( VM_CP, node_pos );
				putCode( frame.value, node_pos );
				putCode( resaddr1, node_pos );
				resaddr1 = frame.value;
				frame.value++;
			}
			int resaddr2 = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );
			SubParam param2 = new SubParam();
			param2.mSubType = stEqual;
			param2.mSubAddress = resaddr2;
			genNodeCode( frame, node.getNode(0), 0, 0, param2 );

			param2.mSubType = stEqual;
			param2.mSubAddress = resaddr1;
			genNodeCode( frame, node.getNode(1), 0, 0, param2 );
			return 0;
		}
		case Token.T_EQUAL:	// '='
		{
			if( param.mSubType != 0 ) mBlock.error( Error.CannotModifyLHS );
			if( (restype & RT_CFLAG) != 0 ) {
				outputWarning( Error.SubstitutionInBooleanContext, node_pos );
			}
			resaddr = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, param );
			SubParam  param2 = new SubParam();
			param2.mSubType = stEqual;
			param2.mSubAddress = resaddr;
			genNodeCode( frame, node.getNode(0), 0, 0, param2 );
			return resaddr;
		}
		case Token.T_AMPERSANDEQUAL:	// '&=' operator
		case Token.T_VERTLINEEQUAL:		// '|=' operator
		case Token.T_CHEVRONEQUAL:		// '^=' operator
		case Token.T_MINUSEQUAL:		// ^-=' operator
		case Token.T_PLUSEQUAL:			// '+=' operator
		case Token.T_PERCENTEQUAL:		// '%=' operator
		case Token.T_SLASHEQUAL:		// '/=' operator
		case Token.T_BACKSLASHEQUAL:	// '\=' operator
		case Token.T_ASTERISKEQUAL:		// '*=' operator
		case Token.T_LOGICALOREQUAL:	// '||=' operator
		case Token.T_LOGICALANDEQUAL:	// '&&=' operator
		case Token.T_RARITHSHIFTEQUAL:	// '>>=' operator
		case Token.T_LARITHSHIFTEQUAL:	// '<<=' operator
		case Token.T_RBITSHIFTEQUAL:	// '>>>=' operator
		{
			if( param.mSubType != 0 ) mBlock.error( Error.CannotModifyLHS );
			resaddr = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );
			SubParam param2 = new SubParam();
			switch(node.getOpecode()) // this may be sucking...
			{
			case Token.T_AMPERSANDEQUAL:	param2.mSubType = stBitAND;		break;
			case Token.T_VERTLINEEQUAL:		param2.mSubType = stBitOR;		break;
			case Token.T_CHEVRONEQUAL:		param2.mSubType = stBitXOR;		break;
			case Token.T_MINUSEQUAL:		param2.mSubType = stSub;		break;
			case Token.T_PLUSEQUAL:			param2.mSubType = stAdd;		break;
			case Token.T_PERCENTEQUAL:		param2.mSubType = stMod;		break;
			case Token.T_SLASHEQUAL:		param2.mSubType = stDiv;		break;
			case Token.T_BACKSLASHEQUAL:	param2.mSubType = stIDiv;		break;
			case Token.T_ASTERISKEQUAL:		param2.mSubType = stMul;		break;
			case Token.T_LOGICALOREQUAL:	param2.mSubType = stLogOR;		break;
			case Token.T_LOGICALANDEQUAL:	param2.mSubType = stLogAND;		break;
			case Token.T_RARITHSHIFTEQUAL:	param2.mSubType = stSAR;		break;
			case Token.T_LARITHSHIFTEQUAL:	param2.mSubType = stSAL;		break;
			case Token.T_RBITSHIFTEQUAL:	param2.mSubType = stSR;			break;
			}
			param2.mSubAddress = resaddr;
			return genNodeCode( frame, node.getNode(0), restype, reqresaddr, param2 );
		}
		case Token.T_QUESTION:	// '?' ':' operator
		{
			// three-term operator ( ? : )
			int resaddr1, resaddr2;
			int frame1, frame2;
			resaddr = genNodeCode( frame, node.getNode(0), RT_NEEDED|RT_CFLAG, 0, new SubParam() );
			boolean inv = false;
			if( !(resaddr == GNC_CFLAG || resaddr == GNC_CFLAG_I) ) {
				putCode( VM_TT, node_pos );
				putCode( resaddr, node_pos );
			} else {
				if( resaddr == GNC_CFLAG_I ) inv = true;
			}
			int cur_frame = frame.value;
			int addr1 = mCodeArea.position();
			addJumpList();
			putCode( inv ? VM_JF : VM_JNF, node_pos );
			putCode( 0, node_pos ); // patch
			resaddr1 = genNodeCode( frame, node.getNode(1), restype, reqresaddr, param );
			if( (restype & RT_CFLAG) != 0 ) {
				if( !(resaddr1 == GNC_CFLAG || resaddr1 == GNC_CFLAG_I) ) {
					putCode( VM_TT, node_pos );
					putCode( resaddr1 ); // node_pos はいらないの？
				} else {
					if( resaddr1 == GNC_CFLAG_I ) putCode( VM_NF, node_pos ); // invert flag
				}
			} else {
				if( (restype&RT_NEEDED) != 0 && !(resaddr1 == GNC_CFLAG || resaddr1 == GNC_CFLAG_I) && resaddr1 <= 0 ) {
					putCode( VM_CP, node_pos );
					putCode( frame.value, node_pos );
					putCode( resaddr1, node_pos );
					resaddr1 = frame.value;
					frame.value++;
				}
			}
			frame1 = frame.value;

			int addr2 = mCodeArea.position();
			addJumpList();
			putCode( VM_JMP, node_pos );
			putCode( 0, node_pos ); // patch
			mCodeArea.put(addr1+1, mCodeArea.position()-addr1 ); // patch
			frame.value = cur_frame;
			resaddr2 = genNodeCode( frame, node.getNode(2), restype, reqresaddr, param );
			if( (restype & RT_CFLAG) != 0 ) {
				// condition flag required
				if( !(resaddr2 == GNC_CFLAG || resaddr2 == GNC_CFLAG_I) ) {
					putCode( VM_TT, node_pos );
					putCode( resaddr2 ); // node_pos はいらないの？
				} else {
					if( resaddr2 == GNC_CFLAG_I ) putCode( VM_NF, node_pos ); // invert flag
				}
			} else {
				if( (restype & RT_NEEDED) != 0 && !(resaddr1 == GNC_CFLAG || resaddr1 == GNC_CFLAG_I) && resaddr1 != resaddr2 ) {
					putCode( VM_CP, node_pos );
					putCode( resaddr1, node_pos );
					putCode( resaddr2, node_pos );
					frame.value++;
				}
			}
			frame2 = frame.value;
			mCodeArea.put(addr2+1, mCodeArea.position()-addr2 ); // patch
			frame.value = frame2 < frame1 ? frame1 : frame2;
			return (restype&RT_CFLAG) != 0 ? GNC_CFLAG : resaddr1;
		}
		case Token.T_LOGICALOR:		// '||'
		case Token.T_LOGICALAND:	// '&&'
		{
			// "logical or" and "locical and"
			// these process with th "shortcut" :
			// OR  : does not evaluate right when left results true
			// AND : does not evaluate right when left results false
			if( param.mSubType != 0 ) mBlock.error( Error.CannotModifyLHS );
			int resaddr1, resaddr2;
			resaddr1 = genNodeCode( frame, node.getNode(0), RT_NEEDED|RT_CFLAG, 0, new SubParam() );
			boolean inv = false;
			if( !(resaddr1 == GNC_CFLAG || resaddr1 == GNC_CFLAG_I) ) {
				putCode( VM_TT, node_pos );
				putCode( resaddr1, node_pos );
			}
			if( resaddr1 == GNC_CFLAG_I ) inv = true;
			int addr1 =  mCodeArea.position();
			addJumpList();
			putCode( node.getOpecode() == Token.T_LOGICALOR ? (inv?VM_JNF:VM_JF) : (inv?VM_JF:VM_JNF), node_pos );
			putCode( 0, node_pos ); // *A
			resaddr2 = genNodeCode( frame, node.getNode(1), RT_NEEDED|RT_CFLAG, 0, new SubParam() );
			if( !(resaddr2 == GNC_CFLAG || resaddr2 == GNC_CFLAG_I) ) {
				putCode( inv ? VM_TF : VM_TT, node_pos );
				putCode( resaddr2, node_pos );
			} else {
				if( (inv != false) != (resaddr2==GNC_CFLAG_I) ) {
					putCode( VM_NF, node_pos ); // invert flag
				}
			}
			mCodeArea.put(addr1+1, mCodeArea.position()-addr1 ); // patch
			if( (restype&RT_CFLAG) == 0 ) {
				// requested result type is not condition flag
				if( (resaddr1 == GNC_CFLAG || resaddr1 == GNC_CFLAG_I) || resaddr1 <= 0 ) {
					putCode( inv ? VM_SETNF : VM_SETF, node_pos );
					putCode( frame.value, node_pos );
					resaddr1 = frame.value;
					frame.value++;
				} else {
					putCode( inv ? VM_SETNF : VM_SETF, node_pos );
					putCode( resaddr1, node_pos );
				}
			}
			return (restype&RT_CFLAG) != 0 ? (inv?GNC_CFLAG_I:GNC_CFLAG) : resaddr1;
		}
		case Token.T_INSTANCEOF: // 'instanceof' operator
		{
			// instanceof operator
			int resaddr1, resaddr2;
			resaddr1 = genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, new SubParam() );
			if( resaddr1 <= 0 ) {
				putCode( VM_CP, node_pos );
				putCode( frame.value, node_pos );
				putCode( resaddr1, node_pos );
				resaddr1 = frame.value;
				frame.value++;
			}
			resaddr2 = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );
			putCode( VM_CHKINS, node_pos );
			putCode( resaddr1, node_pos );
			putCode( resaddr2, node_pos );
			return resaddr1;
		}
		case Token.T_VERTLINE:	// '|' operator
		case Token.T_CHEVRON:	// '^' operator
		case Token.T_AMPERSAND:	// binary '&' operator
		case Token.T_RARITHSHIFT:// '>>' operator
		case Token.T_LARITHSHIFT:// '<<' operator
		case Token.T_RBITSHIFT:	// '>>>' operator
		case Token.T_PLUS:		// binary '+' operator
		case Token.T_MINUS:		// '-' operator
		case Token.T_PERCENT:	// '%' operator
		case Token.T_SLASH:		// '/' operator
		case Token.T_BACKSLASH:	// '\' operator
		case Token.T_ASTERISK:	// binary '*' operator
		{
			// general two-term operator
			int resaddr1, resaddr2;
			if( param.mSubType != stNone ) mBlock.error( Error.CannotModifyLHS );
			resaddr1 = genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, new SubParam() );
			if( resaddr1 <= 0 ) {
				putCode( VM_CP, node_pos );
				putCode( frame.value, node_pos );
				putCode( resaddr1, node_pos );
				resaddr1 = frame.value;
				frame.value++;
			}
			resaddr2 = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );
			int code = 0;
			switch( node.getOpecode() ) { // sucking...
			case Token.T_VERTLINE:		code = VM_BOR;		break;
			case Token.T_CHEVRON:		code = VM_BXOR;		break;
			case Token.T_AMPERSAND:		code = VM_BAND;		break;
			case Token.T_RARITHSHIFT:	code = VM_SAR;		break;
			case Token.T_LARITHSHIFT:	code = VM_SAL;		break;
			case Token.T_RBITSHIFT:		code = VM_SR;		break;
			case Token.T_PLUS:			code = VM_ADD;		break;
			case Token.T_MINUS:			code = VM_SUB;		break;
			case Token.T_PERCENT:		code = VM_MOD;		break;
			case Token.T_SLASH:			code = VM_DIV;		break;
			case Token.T_BACKSLASH:		code = VM_IDIV;		break;
			case Token.T_ASTERISK:		code = VM_MUL;		break;
			}
			putCode( code, node_pos );
			putCode( resaddr1, node_pos );
			putCode( resaddr2, node_pos );
			return resaddr1;
		}
		case Token.T_NOTEQUAL:		// '!=' operator
		case Token.T_EQUALEQUAL:	// '==' operator
		case Token.T_DISCNOTEQUAL:	// '!==' operator
		case Token.T_DISCEQUAL:		// '===' operator
		case Token.T_LT:			// '<' operator
		case Token.T_GT:			// '>' operator
		case Token.T_LTOREQUAL:		// '<=' operator
		case Token.T_GTOREQUAL:		// '>=' operator
		{
			// comparison operators
			int resaddr1, resaddr2;
			if( param.mSubType != stNone ) mBlock.error( Error.CannotModifyLHS );
			resaddr1 = genNodeCode( frame, node.getNode(0), RT_NEEDED, 0 , new SubParam() );
			if( (restype&RT_CFLAG) == 0 ) {
				if( resaddr1 <= 0 ) {
					putCode( VM_CP, node_pos );
					putCode( frame.value, node_pos );
					putCode( resaddr1, node_pos );
					resaddr1 = frame.value;
					frame.value++;
				}
			}
			resaddr2 = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );
			int code1 = 0, code2 = 0;
			switch( node.getOpecode() ) {
			case Token.T_NOTEQUAL:		code1 = VM_CEQ;		code2 = VM_SETNF; 	break;
			case Token.T_EQUALEQUAL:	code1 = VM_CEQ;		code2 = VM_SETF;	break;
			case Token.T_DISCNOTEQUAL:	code1 = VM_CDEQ;	code2 = VM_SETNF;	break;
			case Token.T_DISCEQUAL:		code1 = VM_CDEQ;	code2 = VM_SETF;	break;
			case Token.T_LT:			code1 = VM_CLT;		code2 = VM_SETF;	break;
			case Token.T_GT:			code1 = VM_CGT;		code2 = VM_SETF;	break;
			case Token.T_LTOREQUAL:		code1 = VM_CGT;		code2 = VM_SETNF;	break;
			case Token.T_GTOREQUAL:		code1 = VM_CLT;		code2 = VM_SETNF;	break;
			}
			putCode( code1, node_pos );
			putCode( resaddr1, node_pos );
			putCode( resaddr2, node_pos );
			if( (restype&RT_CFLAG) == 0 ) {
				putCode( code2, node_pos );
				putCode( resaddr1, node_pos );
			}
			return (restype&RT_CFLAG) != 0 ? (code2==VM_SETNF?GNC_CFLAG_I:GNC_CFLAG) : resaddr1;
		}

		// ここから一気に
		case Token.T_EXCRAMATION: // pre-positioned '!' operator
		{
			// logical not
			if((param.mSubType != stNone)) mBlock.error(Error.CannotModifyLHS);
			resaddr = genNodeCode(frame, node.getNode(0), restype, reqresaddr, new SubParam());
			if( (restype & RT_CFLAG) == 0 ) {
				// value as return value required
				if(!(resaddr>0)) {
					putCode(VM_CP, node_pos);
					putCode( frame.value, node_pos);
					putCode( resaddr, node_pos);
					resaddr = frame.value;
					frame.value++;
				}
				putCode(VM_LNOT, node_pos);
				putCode( resaddr, node_pos);
				return resaddr;
			} else {
				// condifion flag required
				if(!(resaddr == GNC_CFLAG || resaddr == GNC_CFLAG_I)) {
					putCode(VM_TF, node_pos);
					putCode( resaddr);
					return GNC_CFLAG;
				}
				return resaddr == GNC_CFLAG_I ? GNC_CFLAG : GNC_CFLAG_I; // invert flag
			}
		}

		case Token.T_TILDE:		// '~' operator
		case Token.T_SHARP:		// '#' operator
		case Token.T_DOLLAR:		// '$' operator
		case Token.T_UPLUS:		// unary '+' operator
		case Token.T_UMINUS:		// unary '-' operator
		case Token.T_INVALIDATE:	// 'invalidate' operator
		case Token.T_ISVALID:		// 'isvalid' operator
		case Token.T_EVAL:		// post-positioned '!' operator
		case Token.T_INT:			// 'int' operator
		case Token.T_REAL:		// 'real' operator
		case Token.T_STRING:		// 'string' operator
		case Token.T_OCTET:		// 'octet' operator
		{
			// general unary operators
			if((param.mSubType != stNone)) mBlock.error(Error.CannotModifyLHS);
			resaddr = genNodeCode(frame, node.getNode(0), RT_NEEDED, 0, new SubParam());
			if(!(resaddr>0)) {
				putCode(VM_CP, node_pos);
				putCode( frame.value, node_pos);
				putCode( resaddr, node_pos);
				resaddr = frame.value;
				frame.value++;
			}
			int code = 0;
			switch(node.getOpecode()) {
				case Token.T_TILDE:			code = VM_BNOT;			break;
				case Token.T_SHARP:			code = VM_ASC;			break;
				case Token.T_DOLLAR:		code = VM_CHR;			break;
				case Token.T_UPLUS:			code = VM_NUM;			break;
				case Token.T_UMINUS:		code = VM_CHS;			break;
				case Token.T_INVALIDATE:	code = VM_INV;			break;
				case Token.T_ISVALID:		code = VM_CHKINV;		break;
				case Token.T_TYPEOF:		code = VM_TYPEOF;		break;
				case Token.T_EVAL:			code = (restype & RT_NEEDED) != 0 ? VM_EVAL:VM_EEXP;
					// warn if T_EVAL is used in non-global position
					if( TJS.mWarnOnNonGlobalEvalOperator && mContextType != ContextType.TOP_LEVEL )
						outputWarning( Error.WarnEvalOperator );
					break;

				case Token.T_INT:			code = VM_INT;			break;
				case Token.T_REAL:			code = VM_REAL;			break;
				case Token.T_STRING:		code = VM_STR;			break;
				case Token.T_OCTET:			code = VM_OCTET;		break;
			}
			putCode(code, node_pos);
			putCode( resaddr, node_pos);
			return resaddr;
		}

		case Token.T_TYPEOF:  // 'typeof' operator
		{
			// typeof
			if((param.mSubType != stNone)) mBlock.error(Error.CannotModifyLHS);
			boolean haspropnode;
			ExprNode cnode = node.getNode(0);
			if( cnode.getOpecode() == Token.T_DOT || cnode.getOpecode() == Token.T_LBRACKET ||
				cnode.getOpecode() == Token.T_WITHDOT)
				haspropnode = true;
			else
				haspropnode = false;

			if(haspropnode) {
				// has property access node
				SubParam param2 = new SubParam();
				param2.mSubType = stTypeOf;
				return genNodeCode(frame, cnode, RT_NEEDED, 0, param2);
			} else {
				// normal operation
				resaddr = genNodeCode(frame, cnode, RT_NEEDED, 0, new SubParam());

				if(!(resaddr>0)) {
					putCode(VM_CP, node_pos);
					putCode( frame.value, node_pos);
					putCode( resaddr, node_pos);
					resaddr = frame.value;
					frame.value++;
				}
				putCode(VM_TYPEOF, node_pos);
				putCode( resaddr, node_pos);
				return resaddr;
			}
		}

		case Token.T_DELETE:			// 'delete' operator
		case Token.T_INCREMENT:		// pre-positioned '++' operator
		case Token.T_DECREMENT:		// pre-positioned '--' operator
		case Token.T_POSTINCREMENT:	// post-positioned '++' operator
		case Token.T_POSTDECREMENT:	// post-positioned '--' operator
		{
			// delete, typeof, increment and decrement
			if((param.mSubType != stNone)) mBlock.error(Error.CannotModifyLHS);
			SubParam param2 = new SubParam();
			switch( node.getOpecode() ) {
			case Token.T_TYPEOF:		param2.mSubType = stTypeOf;		break;
			case Token.T_DELETE:		param2.mSubType = stDelete;		break;
			case Token.T_INCREMENT:		param2.mSubType = stPreInc;		break;
			case Token.T_DECREMENT:		param2.mSubType = stPreDec;		break;
			case Token.T_POSTINCREMENT:	param2.mSubType = stPostInc;	break;
			case Token.T_POSTDECREMENT:	param2.mSubType = stPostDec;	break;
			}
			return genNodeCode(frame, node.getNode(0), restype, reqresaddr, param2);
		}

		case Token.T_LPARENTHESIS:	// '( )' operator
		case Token.T_NEW:			// 'new' operator
		{
			// function call or create-new object

			// does (*node)[0] have a node that acceesses any properties ?
			boolean haspropnode, hasnonlocalsymbol;
			ExprNode cnode = node.getNode(0);
			if(node.getOpecode() == Token.T_LPARENTHESIS &&
				(cnode.getOpecode() == Token.T_DOT || cnode.getOpecode() == Token.T_LBRACKET))
				haspropnode = true;
			else
				haspropnode = false;

			// does (*node)[0] have a node that accesses non-local functions ?
			if(node.getOpecode() == Token.T_LPARENTHESIS && cnode.getOpecode() == Token.T_SYMBOL) {
				if( mAsGlobalContextMode ) {
					hasnonlocalsymbol = true;
				} else {
					String str = cnode.getValue().asString();
					if(mNamespace.find( str ) == -1)
						hasnonlocalsymbol = true;
					else
						hasnonlocalsymbol = false;
				}
			} else {
				hasnonlocalsymbol = false;
			}

			// flag which indicates whether to do direct or indirect call access
			boolean do_direct_access = haspropnode || hasnonlocalsymbol;

			// reserve frame
			if(!do_direct_access && (restype & RT_NEEDED) != 0 )
				frame.value++; // reserve the frame for a result value

			// generate function call codes
			startFuncArg();
			int framestart = frame.value;
			int res;
			try {
				// arguments is

				if( node.getNode(1).getSize() == 1 && node.getNode(1).getNode(0) == null ) {
					// empty
				} else {
					// exist
					genNodeCode(frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );
				}

				// compilation of expression that represents the function
				SubParam param2 = new SubParam();
				if(do_direct_access) {
					param2.mSubType = stFuncCall; // creates code with stFuncCall
					res = genNodeCode(frame, node.getNode(0), restype, reqresaddr, param2);
				} else {
					param2.mSubType = stNone;
					resaddr = genNodeCode(frame, node.getNode(0), RT_NEEDED, 0, param2);

					// code generatio of function calling
					putCode( node.getOpecode() == Token.T_NEW ? VM_NEW: VM_CALL, node_pos);
					putCode((
						res = (restype & RT_NEEDED) != 0 ?(framestart-1):0),
						node_pos); // result target
					putCode( resaddr,
						node_pos); // iTJSDispatch2 that points the function

					// generate argument code
					generateFuncCallArgCode();

					// clears the frame
					clearFrame( frame, framestart );
				}
			} finally {
				endFuncArg();
			}
			return res;
		}

		case Token.T_ARG:
			// a function argument
			if( node.getSize() >= 2 ) {
				if( node.getNode(1) != null ) genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam());
			}
			if( node.getNode(0) != null ) {
				ExprNode n = node.getNode(0);
				if( n.getOpecode() == Token.T_EXPANDARG ) {
					// expanding argument
					if( n.getNode(0) != null )
						addFuncArg( genNodeCode( frame, n.getNode(0), RT_NEEDED, 0, new SubParam()), fatExpand);
					else
						addFuncArg(0, fatUnnamedExpand);
				}
				else
				{
					addFuncArg( genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, new SubParam()), fatNormal);
				}
			} else {
				addFuncArg(0, fatNormal);
			}
			return 0;

		case Token.T_OMIT:
			// omitting of the function arguments
			addOmitArg();
	        return 0;

		case Token.T_DOT:			// '.' operator
		case Token.T_LBRACKET:	// '[ ]' operator
		{
			// member access ( direct or indirect )
			boolean direct = node.getOpecode() == Token.T_DOT;
			int dp;

			SubParam param2 = new SubParam();
			param2.mSubType = stNone;
			resaddr = genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, param2);

			if(direct)
				dp = putData( node.getNode(1).getValue() );
			else
				dp = genNodeCode( frame, node.getNode(1), RT_NEEDED, 0, new SubParam() );

			switch(param.mSubType) {
			case stNone:
			case stIgnorePropGet:
				if(param.mSubType == stNone)
					putCode(direct ? VM_GPD : VM_GPI, node_pos);
				else
					putCode(direct ? VM_GPDS : VM_GPIS, node_pos);
				putCode( frame.value, node_pos);
				putCode( resaddr, node_pos);
				putCode( dp, node_pos);
				frame.value++;
				return frame.value-1;

			case stEqual:
			case stIgnorePropSet:
				if(param.mSubType == stEqual) {
					if( node.getNode(0).getOpecode() == Token.T_THIS_PROXY )
						putCode(direct ? VM_SPD : VM_SPI, node_pos);
					else
						putCode(direct ? VM_SPDE : VM_SPIE, node_pos);
				} else {
					putCode(direct ? VM_SPDS : VM_SPIS, node_pos);
				}
				putCode( resaddr, node_pos);
				putCode( dp, node_pos);
				putCode( param.mSubAddress, node_pos);
				return param.mSubAddress;

			case stBitAND:
			case stBitOR:
			case stBitXOR:
			case stSub:
			case stAdd:
			case stMod:
			case stDiv:
			case stIDiv:
			case stMul:
			case stLogOR:
			case stLogAND:
			case stSAR:
			case stSAL:
			case stSR:
				putCode( param.mSubType + (direct?1:2), node_pos);
					// here adds 1 or 2 to the ope-code
					// ( see the ope-code's positioning order )
				putCode(( (restype & RT_NEEDED) != 0 ? frame.value : 0), node_pos);
				putCode( resaddr, node_pos);
				putCode( dp, node_pos);
				putCode( param.mSubAddress, node_pos);
				if( (restype & RT_NEEDED) != 0 ) frame.value++;
				return (restype & RT_NEEDED) != 0 ?frame.value-1:0;

			case stPreInc:
			case stPreDec:
				putCode((param.mSubType == stPreInc ? VM_INC : VM_DEC) + (direct? 1:2), node_pos);
				putCode(((restype & RT_NEEDED) != 0 ? frame.value : 0), node_pos);
				putCode( resaddr, node_pos);
				putCode( dp, node_pos);
				if( (restype & RT_NEEDED) != 0 ) frame.value++;
				return (restype & RT_NEEDED) != 0 ?frame.value-1:0;

			case stPostInc:
			case stPostDec:
			{
				int retresaddr = 0;
				if( (restype & RT_NEEDED) != 0 ) {
					// need result ...
					putCode(direct ? VM_GPD : VM_GPI, node_pos);
					putCode( frame.value, node_pos);
					putCode( resaddr, node_pos);
					putCode( dp, node_pos);
					retresaddr = frame.value;
					frame.value++;
				}
				putCode( (param.mSubType == stPostInc ? VM_INC : VM_DEC) + (direct? 1:2), node_pos);
				putCode( 0, node_pos );
				putCode( resaddr, node_pos );
				putCode( dp, node_pos );
				return retresaddr;
			}
			case stTypeOf:
			{
				// typeof
				putCode(direct? VM_TYPEOFD:VM_TYPEOFI, node_pos);
				putCode(( (restype & RT_NEEDED) != 0 ? frame.value:0), node_pos);
				putCode( resaddr, node_pos);
				putCode( dp, node_pos);
				if( (restype & RT_NEEDED) != 0 ) frame.value++;
				return (restype & RT_NEEDED) != 0 ? frame.value-1:0;
			}
			case stDelete:
			{
				// deletion
				putCode(direct? VM_DELD:VM_DELI, node_pos);
				putCode(( (restype & RT_NEEDED) != 0 ? frame.value:0), node_pos);
				putCode( resaddr, node_pos);
				putCode( dp, node_pos);
				if( (restype & RT_NEEDED) != 0 ) frame.value++;
				return (restype & RT_NEEDED) != 0 ? frame.value-1:0;
			}
			case stFuncCall:
			{
				// function call
				putCode(direct ? VM_CALLD:VM_CALLI, node_pos);
				putCode(( (restype & RT_NEEDED) != 0 ? frame.value:0), node_pos); // result target
				putCode( resaddr, node_pos); // the object
				putCode( dp, node_pos); // function name

				// generate argument code
				generateFuncCallArgCode();

				// extend frame and return
				if( (restype & RT_NEEDED) != 0 ) frame.value++;
				return (restype & RT_NEEDED) != 0 ? frame.value-1:0;
			}

			default:
				mBlock.error(Error.CannotModifyLHS);
				return 0;
			}
		}


		case Token.T_SYMBOL:	// symbol
		{
			// accessing to a variable
			int n;
			if( mAsGlobalContextMode ) {
				n = -1; // global mode cannot access local variables
			} else {
				String str = node.getValue().asString();
				n = mNamespace.find( str );
			}

			if(n!=-1) {
				boolean isstnone = !(param.mSubType != stNone);

				if(!isstnone) {
					// substitution, or like it
					switch(param.mSubType){
					case stEqual:
						putCode(VM_CP, node_pos);
						putCode((-n-mVariableReserveCount-1), node_pos);
						putCode( param.mSubAddress, node_pos);
						break;

					case stBitAND:
					case stBitOR:
					case stBitXOR:
					case stSub:
					case stAdd:
					case stMod:
					case stDiv:
					case stIDiv:
					case stMul:
					case stLogOR:
					case stLogAND:
					case stSAR:
					case stSAL:
					case stSR:
						putCode(param.mSubType, node_pos);
						putCode((-n-mVariableReserveCount-1), node_pos);
						putCode( param.mSubAddress, node_pos);
						return (restype & RT_NEEDED) != 0 ? -n-mVariableReserveCount-1:0;

					case stPreInc: // pre-positioning
						putCode(VM_INC, node_pos);
						putCode((-n-mVariableReserveCount-1), node_pos);
						return (restype & RT_NEEDED) != 0 ?-n-mVariableReserveCount-1:0;

					case stPreDec: // pre-
						putCode(VM_DEC, node_pos);
						putCode((-n-mVariableReserveCount-1), node_pos);
						return (restype & RT_NEEDED) != 0 ? -n-mVariableReserveCount-1:0;

					case stPostInc: // post-
						if( (restype & RT_NEEDED) != 0 ) {
							putCode(VM_CP, node_pos);
							putCode( frame.value, node_pos);
							putCode((-n-mVariableReserveCount-1), node_pos);
							frame.value++;
						}
						putCode(VM_INC, node_pos);
						putCode((-n-mVariableReserveCount-1), node_pos);
						return (restype & RT_NEEDED) != 0 ? frame.value-1:0;

					case stPostDec: // post-
						if( (restype & RT_NEEDED) != 0 ) {
							putCode(VM_CP, node_pos);
							putCode( frame.value, node_pos);
							putCode((-n-mVariableReserveCount-1), node_pos);
							frame.value++;
						}
						putCode(VM_DEC, node_pos);
						putCode((-n-mVariableReserveCount-1), node_pos);
						return (restype & RT_NEEDED) != 0 ? frame.value-1:0;

					case stDelete: // deletion
					{
						String str = node.getValue().asString();
						mNamespace.remove(str);
						if( (restype & RT_NEEDED) != 0 ) {
							int dp = putData( new Variant(1) ); // true
							putCode(VM_CONST, node_pos);
							putCode( frame.value, node_pos);
							putCode( dp, node_pos);
							return frame.value-1;
						}
						return 0;
					}
					default:
						mBlock.error(Error.CannotModifyLHS);
					}
					return 0;
				} else {
					// read
					String str = node.getValue().asString();
					int n1 = mNamespace.find( str );
					return -n1-mVariableReserveCount-1;
				}
			} else {
				// n==-1 ( indicates the variable is not found in the local  )
				// assume the variable is in "this".
				// make nodes that refer "this" and process it
				ExprNode nodep = new ExprNode();
				nodep.setOpecode(Token.T_DOT);
				nodep.setPosition(node_pos);
				ExprNode node1 = new ExprNode();
				mNodeToDeleteVector.add(node1);
				nodep.add(node1);
				node1.setOpecode(mAsGlobalContextMode ? Token.T_GLOBAL:Token.T_THIS_PROXY);
				node1.setPosition(node_pos);
				ExprNode node2 = new ExprNode();
				mNodeToDeleteVector.add(node2);
				nodep.add(node2);
				node2.setOpecode(Token.T_SYMBOL);
				node2.setPosition(node_pos);
				node2.setValue(node.getValue());
				return genNodeCode( frame, nodep, restype, reqresaddr, param );
			}
		}

		case Token.T_IGNOREPROP: // unary '&' operator
		case Token.T_PROPACCESS: // unary '*' operator
			if( node.getOpecode() == (TJS.mUnaryAsteriskIgnoresPropAccess?Token.T_PROPACCESS:Token.T_IGNOREPROP)) {
				// unary '&' operator
				// substance accessing (ignores property operation)
			  	SubParam sp = new SubParam(param);
				if( sp.mSubType == stNone) sp.mSubType = stIgnorePropGet;
				else if(sp.mSubType == stEqual) sp.mSubType = stIgnorePropSet;
				else mBlock.error(Error.CannotModifyLHS);
				return genNodeCode(frame, node.getNode(0), restype, reqresaddr, sp);
			} else {
				// unary '*' operator
				// force property access
				resaddr = genNodeCode(frame, node.getNode(0), RT_NEEDED, 0, new SubParam() );
				switch(param.mSubType) {
				case stNone: // read from property object
					putCode(VM_GETP, node_pos);
					putCode( frame.value, node_pos);
					putCode( resaddr, node_pos);
					frame.value++;
					return frame.value - 1;

				case stEqual: // write to property object
					putCode(VM_SETP, node_pos);
					putCode( resaddr, node_pos);
					putCode( param.mSubAddress, node_pos);
					return param.mSubAddress;

				case stBitAND:
				case stBitOR:
				case stBitXOR:
				case stSub:
				case stAdd:
				case stMod:
				case stDiv:
				case stIDiv:
				case stMul:
				case stLogOR:
				case stLogAND:
				case stSAR:
				case stSAL:
				case stSR:
					putCode(param.mSubType + 3, node_pos);
						// +3 : property access
						// ( see the ope-code's positioning order )
					putCode(((restype & RT_NEEDED) != 0 ? frame.value: 0), node_pos);
					putCode( resaddr, node_pos);
					putCode( param.mSubAddress, node_pos);
					if( (restype & RT_NEEDED) != 0 ) frame.value++;
					return (restype & RT_NEEDED) != 0 ? frame.value-1:0;

				case stPreInc:
				case stPreDec:
					putCode((param.mSubType == stPreInc ? VM_INC : VM_DEC) + 3, node_pos);
					putCode(((restype & RT_NEEDED) != 0 ? frame.value : 0), node_pos);
					putCode( resaddr, node_pos);
					if( (restype & RT_NEEDED) != 0 ) frame.value++;
					return (restype & RT_NEEDED) != 0 ? frame.value-1:0;

				case stPostInc:
				case stPostDec:
				{
					int retresaddr = 0;
					if( (restype & RT_NEEDED) != 0 ) {
						// need result ...
						putCode(VM_GETP, node_pos);
						putCode( frame.value, node_pos);
						putCode( resaddr, node_pos);
						retresaddr = frame.value;
						frame.value++;
					}
					putCode((param.mSubType == stPostInc ? VM_INC : VM_DEC) + 3, node_pos);
					putCode( 0, node_pos);
					putCode( resaddr, node_pos);
					return retresaddr;
				}

				default:
					mBlock.error(Error.CannotModifyLHS);
					return 0;
				}
			}


		case Token.T_SUPER: // 'super'
		{
			// refer super class
			//int dp;
			ExprNode node1;
			if( mParent != null && mParent.mContextType == ContextType.PROPERTY ) {
				if( (node1 = mParent.mParent.mSuperClassExpr) == null ) {
					mBlock.error(Error.CannotGetSuper);
					return 0;
				}
			} else {
				if( mParent == null || (node1 = mParent.mSuperClassExpr) == null ) {
					mBlock.error(Error.CannotGetSuper);
					return 0;
				}
			}

			mAsGlobalContextMode = true;
			// the code must be generated in global context

			try {
				resaddr = genNodeCode(frame, node1, restype, reqresaddr, param);
			} finally {
				mAsGlobalContextMode = false;
			}

			return resaddr;
		}

		case Token.T_THIS:
			if( param.mSubType != 0 ) mBlock.error(Error.CannotModifyLHS);
			return -1;

		case Token.T_THIS_PROXY:
			// this-proxy is a special register that points
			// both "objthis" and "global"
			// if refering member is not in "objthis", this-proxy
			// refers "global".
			return -mVariableReserveCount;

		case Token.T_WITHDOT: // unary '.' operator
		{
			// dot operator omitting object name
			ExprNode nodep = new ExprNode();
			nodep.setOpecode(Token.T_DOT);
			nodep.setPosition(node_pos);
			ExprNode node1 = new ExprNode();
			mNodeToDeleteVector.add(node1);
			nodep.add(node1);
			node1.setOpecode(Token.T_WITHDOT_PROXY);
			node1.setPosition(node_pos);
			nodep.add( node.getNode(0) );
			return genNodeCode(frame, nodep, restype, reqresaddr, param);
	 	}

		case Token.T_WITHDOT_PROXY:
		{
			// virtual left side of "." operator which omits object

			// search in NestVector
			int i = mNestVector.size() -1;
			for(; i>=0; i--) {
				NestData data = mNestVector.get(i);
				if( data.Type == ntWith ) {
					// found
					return data.RefRegister;
				}
			}

			// not found in NestVector ...
		}
		// NO "break" HERE!!!!!! (pass thru to global)

		case Token.T_GLOBAL:
		{
			if( param.mSubType != 0 ) mBlock.error(Error.CannotModifyLHS);
			if( (restype & RT_NEEDED) == 0 ) return 0;
			putCode(VM_GLOBAL, node_pos);
			putCode( frame.value, node_pos);
			frame.value++;
			return frame.value-1;
		}

		case Token.T_INLINEARRAY:
		{
			// inline array
			int arraydp = putData( new Variant( "Array") );
			//	global %frame0
			//	gpd %frame1, %frame0 . #arraydp // #arraydp = Array
			int frame0 = frame.value;
			putCode(VM_GLOBAL, node_pos);
			putCode((frame.value+0), node_pos);
			putCode(VM_GPD, node_pos);
			putCode((frame.value+1), node_pos);
			putCode((frame.value+0), node_pos);
			putCode( arraydp, node_pos);
			//	new %frame0, %frame1()
			putCode(VM_NEW, node_pos);
			putCode((frame.value+0), node_pos);
			putCode((frame.value+1), node_pos);
			putCode(0);  // argument count for "new Array"
			//	const %frame1, #zerodp
			int zerodp = putData( new Variant(0) );
			putCode(VM_CONST, node_pos);
			putCode((frame.value+1), node_pos);
			putCode( zerodp, node_pos);
			frame.value += 2;

			mArrayArgStack.push( new ArrayArg() );
			mArrayArgStack.peek().Object = frame0;
			mArrayArgStack.peek().Counter = frame0 + 1;

			int nodesize = node.getSize();
			if( node.getSize() == 1 && node.getNode(0).getNode(0) == null ) {
				// the element is empty
			} else {
				for( int i = 0; i<nodesize; i++) {
					genNodeCode(frame, node.getNode(i), RT_NEEDED, 0, new SubParam() ); // elements
				}
			}

			mArrayArgStack.pop();
			return (restype & RT_NEEDED) != 0 ? (frame0):0;
		}

		case Token.T_ARRAYARG:
		{
			// an element of inline array
			int framestart = frame.value;

			resaddr = node.getNode(0) != null ? genNodeCode( frame, node.getNode(0), RT_NEEDED, 0, new SubParam()):0;

			// spis %object.%count, %resaddr
			putCode(VM_SPIS, node_pos);
			putCode((mArrayArgStack.peek().Object));
			putCode((mArrayArgStack.peek().Counter));
			putCode( resaddr);
			// inc %count
			putCode(VM_INC);
			putCode((mArrayArgStack.peek().Counter));

			clearFrame(frame, framestart);

			return 0;
		}


		case Token.T_INLINEDIC:
		{
			// inline dictionary
			int dicdp = putData( new Variant( "Dictionary" ) );
			//	global %frame0
			//	gpd %frame1, %frame0 . #dicdp // #dicdp = Dictionary
			int frame0 = frame.value;
			putCode(VM_GLOBAL, node_pos);
			putCode((frame.value+0), node_pos);
			putCode(VM_GPD, node_pos);
			putCode((frame.value+1), node_pos);
			putCode((frame.value+0), node_pos);
			putCode( dicdp, node_pos);
			//	new %frame0, %frame1()
			putCode(VM_NEW, node_pos);
			putCode((frame.value+0), node_pos);
			putCode((frame.value+1), node_pos);
			putCode(0);  // argument count for "Dictionary" class
			frame.value += 2;
			clearFrame(frame, frame0 + 1);  // clear register at frame+1

			mArrayArgStack.push(new ArrayArg());
			mArrayArgStack.peek().Object = frame0;

			int nodesize = node.getSize();
			for( int i = 0; i < nodesize; i++) {
				genNodeCode(frame, node.getNode(i), RT_NEEDED, 0, new SubParam()); // element
			}

			mArrayArgStack.pop();
			return (restype & RT_NEEDED) != 0 ? (frame0): 0;
		}

		case Token.T_DICELM:
		{
			// an element of inline dictionary
			int framestart = frame.value;
			int name;
			int value;
			name = genNodeCode(frame, node.getNode(0), RT_NEEDED, 0, new SubParam());
			value = genNodeCode(frame, node.getNode(1), RT_NEEDED, 0, new SubParam());
			// spis %object.%name, %value
			putCode(VM_SPIS, node_pos);
			putCode((mArrayArgStack.peek().Object));
			putCode( name);
			putCode( value);

			clearFrame(frame, framestart);

			return 0;
		}

		case Token.T_REGEXP:
		{
			// constant regular expression
			if( (restype & RT_NEEDED) == 0 ) return 0;
			int regexpdp = putData( new Variant( "RegExp" ));
			int patdp = putData(node.getValue());
			int compiledp = putData( new Variant( "_compile" ) );
			// global %frame0
			//	gpd %frame1, %frame0 . #regexpdp // #regexpdp = RegExp
			int frame0 = frame.value;
			putCode(VM_GLOBAL, node_pos);
			putCode( frame.value);
			putCode(VM_GPD);
			putCode((frame.value + 1));
			putCode( frame.value);
			putCode( regexpdp);
			// const frame2, patdp;
			putCode(VM_CONST);
			putCode((frame.value + 2));
			putCode( patdp);
			// new frame0 , frame1();
			putCode(VM_NEW);
			putCode( frame.value);
			putCode((frame.value+1));
			putCode(0);
			// calld 0, frame0 . #compiledp(frame2)
			putCode(VM_CALLD);
			putCode( 0);
			putCode( frame0);
			putCode( compiledp);
			putCode(1);
			putCode((frame.value+2));
			frame.value+=3;
			clearFrame(frame, frame0 + 1);

			return frame0;
		}

		case Token.T_VOID:
			if( param.mSubType != 0 ) mBlock.error( Error.CannotModifyLHS );
			if( (restype & RT_NEEDED) == 0 ) return 0;
			return 0; // 0 is always void
		}
		return 0;
	}
	private void addOmitArg() throws CompileException {
		// omit of the function arguments
		if( mContextType != ContextType.FUNCTION && mContextType != ContextType.EXPR_FUNCTION ) {
			mBlock.error( Error.CannotOmit );
		}
		mFuncArgStack.peek().IsOmit = true;
	}
	private void endFuncArg() {
		// notify the end of function arguments
		mFuncArgStack.pop();

	}
	private void startFuncArg() {
		// notify the start of function arguments
		// create a stack for function arguments
		FuncArg arg = new FuncArg();
		mFuncArgStack.push(arg);
	}
	private void outputWarning( String mes ) {
		outputWarning( mes,-1 );
	}
	private void outputWarning( String mes, int pos ) {
		int errpos = pos == -1 ? mBlock.getLexicalAnalyzer().getCurrentPosition(): pos;

		StringBuilder strBuilder = new StringBuilder(512);
		strBuilder.append(Error.Warning);
		strBuilder.append(mes);
		strBuilder.append(" at ");
		strBuilder.append(mBlock.getName());
		strBuilder.append(" line ");
		strBuilder.append(String.valueOf( 1 + mBlock.srcPosToLine(errpos) ) );

		//mBlock.getTJS().outputToConsole( strBuilder.toString() );
		TJS.outputToConsole( strBuilder.toString() );
		strBuilder = null;
	}
	private void addFuncArg(int addr, int type ) {
		// add a function argument
		// addr = register address to add
		mFuncArgStack.peek().ArgVector.add( new FuncArgItem(addr, type) );
		if( type == fatExpand || type == fatUnnamedExpand )
			mFuncArgStack.peek().HasExpand = true; // has expanding node
	}
	void addJumpList() { mJumpList.add( Integer.valueOf(mCodeArea.position()) ); }
	public void commit() throws VariantException, TJSException {
		// some context-related processing at final, and commits it
		if( mContextType == ContextType.CLASS ) {
			// clean up super class proxy
			if( mSuperClassGetter != null ) mSuperClassGetter.commit();
		}

		if(mContextType != ContextType.PROPERTY && mContextType != ContextType.SUPER_CLASS_GETTER ) {
			int lexpos = getLexPos();
			putCode( VM_SRV, lexpos );
			putCode( 0 );
			putCode( VM_RET );
		}

		registerFunction();

		if( mContextType != ContextType.PROPERTY && mContextType != ContextType.SUPER_CLASS_GETTER ) fixCode();

		/*
		 データエリアのコピーは不要かな。
		if( !DataArea ) {
			DataArea = new tTJSVariant[_DataAreaSize];
			DataAreaSize = _DataAreaSize;

			for(tjs_int i = 0; i<_DataAreaSize; i++) {
				DataArea[i].CopyRef( *_DataArea[i]);
			}

			if(_DataArea) {
				for(tjs_int i = 0; i<_DataAreaSize; i++) delete _DataArea[i];
				TJS_free(_DataArea);
				_DataArea = NULL;
			}
		}
		*/

		if( mContextType == ContextType.SUPER_CLASS_GETTER )
			mMaxVariableCount = 2; // always 2
		else
			mMaxVariableCount = mNamespace.getMaxCount();

		mSuperClassExpr = null;

		clearNodesToDelete();

		/*
		// compact SourcePosArray to just size
		if( mSourcePosArraySize != 0 && mSourcePosArray != null ) {
			SourcePosArray = (tSourcePos*)TJS_realloc(SourcePosArray, SourcePosArraySize * sizeof(tSourcePos));
			if(!SourcePosArray) TJS_eTJSScriptError(TJSInsufficientMem, Block, 0);
			SourcePosArrayCapa = SourcePosArraySize;
		} */

		/*
		// compact CodeArea to just size
		if(CodeAreaSize && CodeArea) {
			// must inflate the code area
			CodeArea = (tjs_int32*)TJS_realloc(CodeArea,sizeof(tjs_int32)*CodeAreaSize);
			if(!CodeArea) TJS_eTJSScriptError(TJSInsufficientMem, Block, 0);
			CodeAreaCapa = CodeAreaSize;
		}
		*/


		// set object type info for debugging
		/* デバッグ用の機能はとりあえず省略
		if( Debug.objectHashMapEnabled() )
			TJSObjectHashSetType( this, getShortDescriptionWithClassName() );
		*/


		// we do thus nasty thing because the std::vector does not free its storage
		// even we call 'clear' method...

		mNodeToDeleteVector = null; mNodeToDeleteVector = new VectorWrap<ExprNode>();
		mCurrentNodeVector = null; mCurrentNodeVector = new VectorWrap<ExprNode>();
		mFuncArgStack = null; mFuncArgStack = new Stack<FuncArg>();
		mArrayArgStack = null; mArrayArgStack = new Stack<ArrayArg>();
		mNestVector = null; mNestVector = new VectorWrap<NestData>();
		mJumpList = null; mJumpList = new ArrayList<Integer>();
		mFixList = null; mFixList = new ArrayList<FixData>();
		mNonLocalFunctionDeclVector = null; mNonLocalFunctionDeclVector = new VectorWrap<NonLocalFunctionDecl>();
	}
	private void clearNodesToDelete() {
		if( mNodeToDeleteVector.size() > 0 ) {
			int count = mNodeToDeleteVector.size();
			for( int i = count-1; i >= 0; i-- ) {
				mNodeToDeleteVector.get(i).clear();
			}
		}
		mNodeToDeleteVector.clear();
	}
	private void fixCode() {
		// code re-positioning and patch processing
		// OriginalTODO: InterCodeContext::fixCode fasten the algorithm

		// create 'regmember' instruction to register class members to
		// newly created object
		if( mContextType == ContextType.CLASS ) {
			// generate a code
			ByteBuffer buff = ByteBuffer.allocateDirect(4);
			buff.order( ByteOrder.nativeOrder() );
			IntBuffer code = buff.asIntBuffer();
			code.clear();
			code.put( VM_REGMEMBER );

			// make a patch information
			// use FunctionRegisterCodePoint for insertion point
			mFixList.add( new FixData(mFunctionRegisterCodePoint, 0, 1, code, true));
		}

		// process funtion reservation to enable backward reference of
		// global/method functions
		if( mNonLocalFunctionDeclVector.size() >= 1 ) {
			if( mMaxFrameCount < 1) mMaxFrameCount = 1;

			//std::vector<tNonLocalFunctionDecl>::iterator func;
			Iterator<NonLocalFunctionDecl> func;

			// make function registration code to objthis

			// compute codesize
			int codesize = 2;
			func = mNonLocalFunctionDeclVector.iterator();
			while( func.hasNext() ){
				NonLocalFunctionDecl dec = (NonLocalFunctionDecl)func.next();
				if( dec.ChangeThis ) codesize += 10;
				else codesize += 7;
		    }
			ByteBuffer buff = ByteBuffer.allocateDirect(codesize*4);
			buff.order( ByteOrder.nativeOrder() );
			IntBuffer code = buff.asIntBuffer();
			code.clear();

			// generate code
			func = mNonLocalFunctionDeclVector.iterator();
			while( func.hasNext() ){
				NonLocalFunctionDecl dec = func.next();

				// const %1, #funcdata
				code.put( VM_CONST );
				code.put( 1);
				code.put( dec.DataPos );

				// chgthis %1, %-1
				if( dec.ChangeThis ) {
					code.put( VM_CHGTHIS );
					code.put( 1 );
					code.put( -1 );
				}

				// spds %-1.#funcname, %1
				code.put( VM_SPDS );
				code.put( -1 ); // -1 =  objthis
				code.put( dec.NameDataPos);
				code.put( 1 );
			}

			// cl %1
			code.put( VM_CL );
			code.put( 1 );
			code.flip();

			// make a patch information
			mFixList.add( new FixData(mFunctionRegisterCodePoint, 0, codesize, code, true) );

			mNonLocalFunctionDeclVector.clear();
		}

		// sort SourcePosVector
		sortSourcePos();

		// re-position patch
		int count = mFixList.size();
		for( int i = 0; i < count; i++ ) {
			FixData fix = mFixList.get(i);

			int jcount = mJumpList.size();
			for( int j = 0; j < jcount; j++ ) {
				int jmp = mJumpList.get(j).intValue();
				int jmptarget = mCodeArea.get( jmp + 1 ) + jmp;
				if( jmp >= fix.StartIP && jmp < fix.Size + fix.StartIP ) {
					// jmp is in the re-positioning target -> delete
					mJumpList.remove(j);
					if( (j+1) < jcount ) {
						j++;
						jmp = mJumpList.get(j).intValue();
					} else {
						jmp = 0;
					}
				} else if( fix.BeforeInsertion ?
					(jmptarget < fix.StartIP):(jmptarget <= fix.StartIP)
					&& jmp > fix.StartIP + fix.Size ||
					jmp < fix.StartIP && jmptarget >= fix.StartIP + fix.Size)
				{
					// jmp and its jumping-target is in the re-positioning target
					int v = mCodeArea.get( jmp + 1 );
					v += fix.NewSize - fix.Size;
					mCodeArea.put( jmp+1, v );
				}

				if( jmp >= fix.StartIP + fix.Size) {
					// fix up jmp
					jmp += fix.NewSize - fix.Size;
					mJumpList.set( j, Integer.valueOf(jmp) );
				}
			}

			// move the code
			if( fix.NewSize > fix.Size ) {
				// when code inflates on fixing
				final int newBufferSize = 4 * (mCodeArea.position() + fix.NewSize - fix.Size);
				ByteBuffer buff = ByteBuffer.allocateDirect( newBufferSize );
				buff.order( ByteOrder.nativeOrder() );
				IntBuffer ibuff = buff.asIntBuffer();
				ibuff.clear();
				mCodeArea.flip();
				ibuff.put( mCodeArea );
				mCodeArea = null;
				mCodeArea = ibuff;
			}

			if( mCodeArea.position() - (fix.StartIP + fix.Size) > 0 ) {
				// move the existing code
				int dst = fix.StartIP + fix.NewSize;
				int src = fix.StartIP + fix.Size;
				int size = mCodeArea.position() - (fix.StartIP + fix.Size);

				ByteBuffer buff = ByteBuffer.allocateDirect(size*4);
				buff.order( ByteOrder.nativeOrder() );
				IntBuffer ibuff = buff.asIntBuffer();
				ibuff.clear();
				for( int j = 0; j < size; j++ ) { // テンポラリへコピー
					ibuff.put( j, mCodeArea.get(src+j) );
				}
				for( int j = 0; j < size; j++ ) {
					mCodeArea.put( dst+j, ibuff.get(j) );
				}
				ibuff = null;

				// move sourcepos
				final int srcSize = mSourcePosArray.position();
				for( int j = 0; j < srcSize; j++) {
					long val = mSourcePosArray.get(j);
					val >>>= 32;
					if( val >= fix.StartIP + fix.Size ) {
						val += fix.NewSize - fix.Size;
						val = (val << 32) | (mSourcePosArray.get(j)&0xFFFFFFFFL);
						mSourcePosArray.put( j, val );
					}
				}
			}

			if( fix.NewSize > 0 && fix.Code != null ) {
				// copy the new code
				int size = fix.NewSize;
				int dst = fix.StartIP;
				for( int j = 0; j < size; j++ ) {
					mCodeArea.put( dst+j, fix.Code.get(j) );
				}
			}

			mCodeArea.position( mCodeArea.position() + fix.NewSize-fix.Size );
		}

		// eliminate redundant jump codes
		int jcount = mJumpList.size();
		for( int i = 0; i < jcount; i++ ) {
			int jmp = mJumpList.get(i).intValue();

			int jumptarget = mCodeArea.get( jmp + 1 ) + jmp;
			int jumpcode = mCodeArea.get( jmp );
			int addr = jmp;
			addr += mCodeArea.get( addr + 1 );
			for(;;) {
				if( mCodeArea.get(addr) == VM_JMP ||
					(mCodeArea.get(addr) == jumpcode && (jumpcode == VM_JF || jumpcode == VM_JNF))) {
					// simple jump code or
					// JF after JF or JNF after JNF
					jumptarget = mCodeArea.get(addr + 1) + addr; // skip jump after jump
					if(mCodeArea.get(addr + 1) != 0)
						addr += mCodeArea.get(addr + 1);
					else
						break; // must be an error
				} else if(mCodeArea.get(addr) == VM_JF && jumpcode == VM_JNF || mCodeArea.get(addr) == VM_JNF && jumpcode == VM_JF) {
					// JF after JNF or JNF after JF
					jumptarget = addr + 2;
						// jump code after jump will not jump
					addr += 2;
				}
				else
				{
					// other codes
					break;
				}
			}
			mCodeArea.put( jmp + 1, jumptarget - jmp );
		}

		/* アドレス変換は不要
		// convert jump addresses to VM address
		for(std::list<tjs_int>::iterator jmp = JumpList.begin(); jmp!=JumpList.end(); jmp++) {
			CodeArea[*jmp + 1] = TJS_TO_VM_CODE_ADDR(CodeArea[*jmp + 1]);
		}
		*/

		mJumpList.clear();
		mFixList.clear();
	}
	// クイックソート
	private static int pivot( LongBuffer a, int i, int j ) {
		int k = i + 1;
		while( k <= j && a.get(i) == a.get(k) ) k++;
		if( k > j ) return -1;
		if( a.get(i) >= a.get(k) ) return i;
		return k;
	}
	private static int partition( LongBuffer a, int i, int j, long x ) {
		int l = i, r = j;
		while( l <= r ) {
			while( l <= j && a.get(l) < x )  l++;
			while( r >= i && a.get(r) >= x ) r--;
			if( l > r ) break;
			// swap
			long t = a.get(l);
			a.put( l, a.get(r) );
			a.put( r, t );
			l++; r--;
		}
		return l;
	}
	private static void quickSort( LongBuffer a, int i, int j ){
		if( i == j ) return;
		int p = pivot( a, i, j );
		if( p != -1 ) {
			int k = partition( a, i, j, a.get(p) );
			quickSort( a, i, k-1 );
			quickSort( a, k, j );
		}
	}
	private void sortSourcePos() {
		// 上位をcodePos, 下位をsourcePos とする, codePos でのソートなので下位は気にせずソートししまう
		if( !mSourcePosArraySorted ) {
			quickSort( mSourcePosArray, 0, mSourcePosArray.position()-1 );
			mSourcePosArraySorted = true;
		}
	}
	private void registerFunction() throws VariantException, TJSException {
		// registration of function to the parent's context
		if( mParent == null ) return;

		if( mContextType == ContextType.PROPERTY_SETTER ) {
			mParent.mPropSetter = this;
			return;
		}
		if( mContextType == ContextType.PROPERTY_GETTER ) {
			mParent.mPropGetter = this;
			return;
		}
		if( mContextType == ContextType.SUPER_CLASS_GETTER ) {
			return; // these are already registered to parent context
		}

		if( mContextType != ContextType.FUNCTION &&  // ctExprFunction is not concerned here
			mContextType != ContextType.PROPERTY &&
			mContextType != ContextType.CLASS ) {
			return;
		}

		int data = -1;
		if( mParent.mContextType == ContextType.TOP_LEVEL ) {
			Variant val;
			val = new Variant( this );
			data = mParent.putData(val);
			val = new Variant(mName);
			int name = mParent.putData(val);
			boolean changethis = mContextType == ContextType.FUNCTION || mContextType == ContextType.PROPERTY;
			mParent.mNonLocalFunctionDeclVector.add( new NonLocalFunctionDecl(data, name, changethis) );
		}

		if( mContextType == ContextType.FUNCTION && mParent.mContextType == ContextType.FUNCTION ) {
			// local functions
			// adds the function as a parent's local variable
			if( data == -1 ) {
				Variant val;
				val = new Variant( this );
				data = mParent.putData(val);
			}
			mParent.initLocalFunction( mName, data );
		}

		if( mParent.mContextType == ContextType.FUNCTION || mParent.mContextType == ContextType.CLASS ) {
			// register members to the parent object
			Variant val = new Variant( this );
			mParent.propSet( MEMBERENSURE|IGNOREPROP, mName, null, val, mParent );
		}
	}
	private void executeAsFunction(Dispatch2 objthis, Variant[] args, Variant result, int start_ip ) throws VariantException, TJSException {
		int num_alloc = mMaxVariableCount + mVariableReserveCount + 1 + mMaxFrameCount;
		// TJSVariantArrayStackAddRef();

		try {
			ArrayList<Variant> regs = new ArrayList<Variant>(num_alloc);
			for( int i = 0; i < num_alloc; i++ ) {
				regs.add(null);
			}
			int arrayOffset = mMaxVariableCount + mVariableReserveCount; // register area

			// objthis-proxy
			if( objthis != null ) {
				ObjectProxy proxy = new ObjectProxy();
				proxy.setObjects( objthis, mBlock.getTJS().getGlobal() );
				// OriginalTODO: caching of objthis-proxy

				//ra[-2] = proxy;
				regs.set( arrayOffset-2, new Variant(proxy) );
			} else {
				//proxy.setObjects( null, null );

				Dispatch2 global = mBlock.getTJS().getGlobal();

				//ra[-2].setObject( global, global );
				regs.set( arrayOffset-2, new Variant(global,global) );
			}

//			if( TJSStackTracerEnabled() ) TJSStackTracerPush( this, false );

//			// check whether the objthis is deleting
//			if( TJSWarnOnExecutionOnDeletingObject && TJSObjectFlagEnabled() && mBlock.getTJS().getConsoleOutput() )
//				TJSWarnIfObjectIsDeleting( mBlock.getTJS().getConsoleOutput(), objthis);


			try {
				//ra[-1].SetObject(objthis, objthis);
				regs.set( arrayOffset-1, new Variant(objthis,objthis) );
				//ra[0].Clear();
				regs.set( arrayOffset, new Variant() );

				// transfer arguments
				final int numargs = args != null ? args.length : 0;
				if( numargs >= mFuncDeclArgCount ) {
					// given arguments are greater than or equal to desired arguments
					if( mFuncDeclArgCount != 0 ) {
						//Variant *r = ra - 3;
						int r = arrayOffset - 3;
						//Variant **a = args;
						int n = mFuncDeclArgCount;
						int argOffset = 0;
						while( true ) {
							regs.set( r, args[argOffset] );
							argOffset++;
							//*r = **(a++);
							n--;
							if( n == 0 ) break;
							r--;
						}
					}
				} else {
					// given arguments are less than desired arguments
					//Variant *r = ra - 3;
					int r = arrayOffset - 3;
					//Variant **a = args;
					int argOffset = 0;
					int i;
					for(i = 0; i < numargs; i++) {
						regs.set( r, args[argOffset] );
						argOffset++;
						//*(r--) = **(a++);
						r--;
					}
					for(; i < mFuncDeclArgCount; i++) {
						//(r--)->Clear();
						regs.set( r, new Variant() );
						r--;
					}
				}

				// collapse into array when FuncDeclCollapseBase >= 0
				if( mFuncDeclCollapseBase >= 0 ) {
					//Variant *r = ra - 3 - mFuncDeclCollapseBase; // target variant
					int r = arrayOffset - 3 - mFuncDeclCollapseBase; // target variant
					Dispatch2 dsp = TJS.createArrayObject();
					//*r = new Variant(dsp, dsp);
					regs.set( r, new Variant(dsp, dsp) );
					//dsp->Release();

					if( numargs > mFuncDeclCollapseBase ) {
						// there are arguments to store
						for( int c = 0, i = mFuncDeclCollapseBase; i < numargs; i++, c++) {
							dsp.propSetByNum(0, c, args[i], dsp);
						}
					}
				}

				// execute
				executeCode( regs, arrayOffset, start_ip, args, result);
			} finally {
				regs.get( arrayOffset-2 ).clear();
				//ra[-2].Clear(); // at least we must clear the object placed at local stack
				//TJSVariantArrayStack->Deallocate(num_alloc, regs);
//				if(TJSStackTracerEnabled()) TJSStackTracerPop();
			}
			//ra[-2].Clear(); // at least we must clear the object placed at local stack
			// TJSVariantArrayStack->Deallocate(num_alloc, regs);

//			if(TJSStackTracerEnabled()) TJSStackTracerPop();
		} finally {
			// TJSVariantArrayStackRelease();
		}
	}

	private int executeCode(ArrayList<Variant> ra_org, int ra_offset, int startip, Variant[] args, Variant result) throws TJSScriptError, VariantException {

		// execute VM codes
		int codesave = startip;
		try {
			int code = startip;//mCodeArea.get(startip);

			//if(TJSStackTracerEnabled()) TJSStackTracerSetCodePointer(CodeArea, &codesave);


			ArrayList<Variant> ra = ra_org;
			ArrayList<Variant> da = mDataArea;
			IntBuffer ca = mCodeArea;

			boolean flag = false;
			int op;
			while( true ) {
				codesave = code;
				op = ca.get(code);
				switch( op ) {
				case VM_NOP:
					code++;
					break;

				case VM_CONST:
					//TJS_GET_VM_REG(ra, code[1]).CopyRef(TJS_GET_VM_REG(da, code[2]));
					ra.set(ra_offset+ca.get(code+1), new Variant(da.get(ca.get(code+2))) );
					code += 3;
					break;

				case VM_CP:
					//TJS_GET_VM_REG(ra, code[1]).CopyRef(TJS_GET_VM_REG(ra, code[2]));
					ra.set(ra_offset+ca.get(code+1), new Variant(ra.get(ra_offset+ca.get(code+2))) );
					code += 3;
					break;

				case VM_CL:
					//TJS_GET_VM_REG(ra, code[1]).Clear();
					//ra.get(ra_offset+ca.get(code+1)).clear();
					ra.set(ra_offset+ca.get(code+1), new Variant() );
					code += 2;
					break;

				case VM_CCL:
					continuousClear(ra, ra_offset, code);
					code += 3;
					break;

				case VM_TT:
					//flag = TJS_GET_VM_REG(ra, code[1]).operator bool();
					flag = ra.get(ra_offset+ca.get(code+1)).asBoolean();
					code += 2;
					break;

				case VM_TF:
					//flag = !(TJS_GET_VM_REG(ra, code[1]).operator bool());
					flag = !ra.get(ra_offset+ca.get(code+1)).asBoolean();
					code += 2;
					break;

				case VM_CEQ:
					//flag = TJS_GET_VM_REG(ra, code[1]).NormalCompare( TJS_GET_VM_REG(ra, code[2]));
					flag = ra.get(ra_offset+ca.get(code+1)).normalCompare( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;

				case VM_CDEQ:
					//flag = TJS_GET_VM_REG(ra, code[1]).DiscernCompare( TJS_GET_VM_REG(ra, code[2]));
					flag = ra.get(ra_offset+ca.get(code+1)).discernCompare( ra.get(ra_offset+ca.get(code+2)) ).asBoolean();
					code += 3;
					break;

				case VM_CLT:
					//flag = TJS_GET_VM_REG(ra, code[1]).GreaterThan( TJS_GET_VM_REG(ra, code[2]));
					flag = ra.get(ra_offset+ca.get(code+1)).greaterThan( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;

				case VM_CGT:
					//flag = TJS_GET_VM_REG(ra, code[1]).LittlerThan( TJS_GET_VM_REG(ra, code[2]));
					flag = ra.get(ra_offset+ca.get(code+1)).littlerThan( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;

				case VM_SETF:
					//TJS_GET_VM_REG(ra, code[1]) = flag;
					ra.set(ra_offset+ca.get(code+1),new Variant(flag?1:0) );
					code += 2;
					break;

				case VM_SETNF:
					//TJS_GET_VM_REG(ra, code[1]) = !flag;
					ra.set(ra_offset+ca.get(code+1),new Variant(flag?0:1) );
					code += 2;
					break;

				case VM_LNOT:
					//TJS_GET_VM_REG(ra, code[1]).logicalnot();
					ra.get(ra_offset+ca.get(code+1)).logicalnot();
					code += 2;
					break;

				case VM_NF:
					flag = !flag;
					code ++;
					break;

				case VM_JF:
					// TJS_ADD_VM_CODE_ADDR(dest, x)  ((*(char **)&(dest)) += (x))
					if(flag)
						//TJS_ADD_VM_CODE_ADDR(code, code[1]);
						//code += ra.get(ra_offset+ca.get(code+1)).asInteger();
						code += ca.get(code+1);
					else
						code += 2;
					break;

				case VM_JNF:
					if(!flag)
						//TJS_ADD_VM_CODE_ADDR(code, code[1]);
						//code += ra.get(ra_offset+ca.get(code+1)).asInteger();
						code += ca.get(code+1);
					else
						code += 2;
					break;

				case VM_JMP:
					//TJS_ADD_VM_CODE_ADDR(code, code[1]);
					//code += ra.get(ra_offset+ca.get(code+1)).asInteger();
					code += ca.get(code+1);
					break;

				case VM_INC:
					//TJS_GET_VM_REG(ra, code[1]).increment();
					ra.get(ra_offset+ca.get(code+1)).increment();
					code += 2;
					break;

				case VM_INCPD:
					operatePropertyDirect0(ra, ra_offset, code, OP_INC);
					code += 4;
					break;

				case VM_INCPI:
					operatePropertyIndirect0(ra, ra_offset, code, OP_INC);
					code += 4;
					break;

				case VM_INCP:
					operateProperty0(ra, ra_offset, code, OP_INC);
					code += 3;
					break;

				case VM_DEC:
					//TJS_GET_VM_REG(ra, code[1]).decrement();
					ra.get(ra_offset+ca.get(code+1)).decrement();
					code += 2;
					break;

				case VM_DECPD:
					operatePropertyDirect0(ra, ra_offset, code, OP_DEC);
					code += 4;
					break;

				case VM_DECPI:
					operatePropertyIndirect0(ra, ra_offset, code, OP_DEC);
					code += 4;
					break;

				case VM_DECP:
					operateProperty0(ra, ra_offset, code, OP_DEC);
					code += 3;
					break;


				// TJS_DEF_VM_P
				case VM_LOR:
					ra.get(ra_offset+ca.get(code+1)).logicalorequal( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_LORPD:
					operatePropertyDirect(ra, ra_offset, code, OP_LOR);
					code += 5;
					break;
				case VM_LORPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_LOR );
					code += 5;
					break;
				case VM_LORP:
					operateProperty(ra, ra_offset, code, OP_LOR );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_LAND:
					ra.get(ra_offset+ca.get(code+1)).logicalandequal( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_LANDPD:
					operatePropertyDirect(ra, ra_offset, code, OP_LAND );
					code += 5;
					break;
				case VM_LANDPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_LAND );
					code += 5;
					break;
				case VM_LANDP:
					operateProperty(ra, ra_offset, code, OP_LAND );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_BOR:
					ra.get(ra_offset+ca.get(code+1)).orEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_BORPD:
					operatePropertyDirect(ra, ra_offset, code, OP_BOR );
					code += 5;
					break;
				case VM_BORPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_BOR );
					code += 5;
					break;
				case VM_BORP:
					operateProperty(ra, ra_offset, code, OP_BOR );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_BXOR:
					ra.get(ra_offset+ca.get(code+1)).bitXorEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_BXORPD:
					operatePropertyDirect(ra, ra_offset, code, OP_BXOR );
					code += 5;
					break;
				case VM_BXORPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_BXOR );
					code += 5;
					break;
				case VM_BXORP:
					operateProperty(ra, ra_offset, code, OP_BXOR );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_BAND:
					ra.get(ra_offset+ca.get(code+1)).andEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_BANDPD:
					operatePropertyDirect(ra, ra_offset, code, OP_BAND );
					code += 5;
					break;
				case VM_BANDPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_BAND );
					code += 5;
					break;
				case VM_BANDP:
					operateProperty(ra, ra_offset, code, OP_BAND );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_SAR:
					ra.get(ra_offset+ca.get(code+1)).rightShiftEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_SARPD:
					operatePropertyDirect(ra, ra_offset, code, OP_SAR );
					code += 5;
					break;
				case VM_SARPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_SAR );
					code += 5;
					break;
				case VM_SARP:
					operateProperty(ra, ra_offset, code, OP_SAR );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_SAL:
					ra.get(ra_offset+ca.get(code+1)).leftShiftEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_SALPD:
					operatePropertyDirect(ra, ra_offset, code, OP_SAL );
					code += 5;
					break;
				case VM_SALPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_SAL );
					code += 5;
					break;
				case VM_SALP:
					operateProperty(ra, ra_offset, code, OP_SAL );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_SR:
					ra.get(ra_offset+ca.get(code+1)).rbitshiftequal( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_SRPD:
					operatePropertyDirect(ra, ra_offset, code, OP_SR );
					code += 5;
					break;
				case VM_SRPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_SR );
					code += 5;
					break;
				case VM_SRP:
					operateProperty(ra, ra_offset, code, OP_SR );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_ADD:
					ra.get(ra_offset+ca.get(code+1)).addEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_ADDPD:
					operatePropertyDirect(ra, ra_offset, code, OP_ADD );
					code += 5;
					break;
				case VM_ADDPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_ADD );
					code += 5;
					break;
				case VM_ADDP:
					operateProperty(ra, ra_offset, code, OP_ADD );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_SUB:
					ra.get(ra_offset+ca.get(code+1)).subtractEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_SUBPD:
					operatePropertyDirect(ra, ra_offset, code, OP_SUB );
					code += 5;
					break;
				case VM_SUBPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_SUB );
					code += 5;
					break;
				case VM_SUBP:
					operateProperty(ra, ra_offset, code, OP_SUB );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_MOD:
					ra.get(ra_offset+ca.get(code+1)).residueEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_MODPD:
					operatePropertyDirect(ra, ra_offset, code, OP_MOD );
					code += 5;
					break;
				case VM_MODPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_MOD );
					code += 5;
					break;
				case VM_MODP:
					operateProperty(ra, ra_offset, code, OP_MOD );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_DIV:
					ra.get(ra_offset+ca.get(code+1)).divideEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_DIVPD:
					operatePropertyDirect(ra, ra_offset, code, OP_DIV );
					code += 5;
					break;
				case VM_DIVPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_DIV );
					code += 5;
					break;
				case VM_DIVP:
					operateProperty(ra, ra_offset, code, OP_DIV );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_IDIV:
					ra.get(ra_offset+ca.get(code+1)).idivequal( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_IDIVPD:
					operatePropertyDirect(ra, ra_offset, code, OP_IDIV );
					code += 5;
					break;
				case VM_IDIVPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_IDIV );
					code += 5;
					break;
				case VM_IDIVP:
					operateProperty(ra, ra_offset, code, OP_IDIV );
					code += 4;
					break;
				// TJS_DEF_VM_P
				case VM_MUL:
					ra.get(ra_offset+ca.get(code+1)).multiplyEqual( ra.get(ra_offset+ca.get(code+2)) );
					code += 3;
					break;
				case VM_MULPD:
					operatePropertyDirect(ra, ra_offset, code, OP_MUL );
					code += 5;
					break;
				case VM_MULPI:
					operatePropertyIndirect(ra, ra_offset, code, OP_MUL );
					code += 5;
					break;
				case VM_MULP:
					operateProperty(ra, ra_offset, code, OP_MUL );
					code += 4;
					break;
				// TJS_DEF_VM_P


				case VM_BNOT:
					//TJS_GET_VM_REG(ra, code[1]).bitnot();
					ra.get(ra_offset+ca.get(code+1)).bitnot();
					code += 2;
					break;

				case VM_ASC:
					//CharacterCodeOf(TJS_GET_VM_REG(ra, code[1]));
					characterCodeOf( ra.get(ra_offset+ca.get(code+1)) );
					code += 2;
					break;

				case VM_CHR:
					//CharacterCodeFrom(TJS_GET_VM_REG(ra, code[1]));
					characterCodeFrom( ra.get(ra_offset+ca.get(code+1)) );
					code += 2;
					break;

				case VM_NUM:
					//TJS_GET_VM_REG(ra, code[1]).tonumber();
					ra.get(ra_offset+ca.get(code+1)).tonumber();
					code += 2;
					break;

				case VM_CHS:
					//TJS_GET_VM_REG(ra, code[1]).changesign();
					ra.get(ra_offset+ca.get(code+1)).changesign();
					code += 2;
					break;

				case VM_INV: {
					int offset = ra_offset+ca.get(code+1);
					boolean tmp = ra.get(offset).isObject() == false ? false :
						ra.get(offset).asObjectClosure().invalidate(0, null, null, ra.get(ra_offset-1).asObject()) == S_TRUE;
					ra.set(offset, new Variant(tmp?1:0) );
					/*
					TJS_GET_VM_REG(ra, code[1]) =
						TJS_GET_VM_REG(ra, code[1]).Type() != tvtObject ? false :
						(TJS_GET_VM_REG(ra, code[1]).AsObjectClosureNoAddRef().Invalidate(0,
						NULL, NULL, ra[-1].AsObjectNoAddRef()) == TJS_S_TRUE);
					*/
					code += 2;
					break;
				}

				case VM_CHKINV: {
					int offset = ra_offset+ca.get(code+1);
					boolean tmp;
					if( ra.get(offset).isObject() == false ) {
						tmp = true;
					} else {
						int ret = ra.get(offset).asObjectClosure().isValid(0, null, null, ra.get(ra_offset-1).asObject());
						tmp = ret == S_TRUE || ret == E_NOTIMPL;
					}
					ra.set(offset, new Variant(tmp?1:0) );
					/*
					TJS_GET_VM_REG(ra, code[1]) =
						TJS_GET_VM_REG(ra, code[1]).Type() != tvtObject ? true :
						TJSIsObjectValid(TJS_GET_VM_REG(ra, code[1]).AsObjectClosureNoAddRef().IsValid(0,
						NULL, NULL, ra[-1].AsObjectNoAddRef()));
					*/
					code += 2;
					break;
				}

				case VM_INT:
					//TJS_GET_VM_REG(ra, code[1]).ToInteger();
					ra.get(ra_offset+ca.get(code+1)).toInteger();
					code += 2;
					break;

				case VM_REAL:
					//TJS_GET_VM_REG(ra, code[1]).ToReal();
					ra.get(ra_offset+ca.get(code+1)).toReal();
					code += 2;
					break;

				case VM_STR:
					//TJS_GET_VM_REG(ra, code[1]).ToString();
					ra.get(ra_offset+ca.get(code+1)).selfToString();
					code += 2;
					break;

				case VM_OCTET:
					//TJS_GET_VM_REG(ra, code[1]).ToOctet();
					ra.get(ra_offset+ca.get(code+1)).toOctet();
					code += 2;
					break;

				case VM_TYPEOF:
					//TypeOf(TJS_GET_VM_REG(ra, code[1]));
					typeOf( ra.get(ra_offset+ca.get(code+1)) );
					code += 2;
					break;

				case VM_TYPEOFD:
					typeOfMemberDirect(ra, ra_offset, code, MEMBERMUSTEXIST);
					code += 4;
					break;

				case VM_TYPEOFI:
					typeOfMemberIndirect(ra, ra_offset, code, MEMBERMUSTEXIST);
					code += 4;
					break;

				case VM_EVAL:
					eval( ra.get(ra_offset+ca.get(code+1)) ,
						TJS.mEvalOperatorIsOnGlobal ? null : ra.get(ra_offset-1).asObject(),
						true);
					code += 2;
					break;

				case VM_EEXP:
					eval( ra.get(ra_offset+ca.get(code+1)) ,
						TJS.mEvalOperatorIsOnGlobal ? null : ra.get(ra_offset-1).asObject(),
						false);
					code += 2;
					break;

				case VM_CHKINS:
					instanceOf( ra.get(ra_offset+ca.get(code+2)) , ra.get(ra_offset+ca.get(code+1)) );
					code += 3;
					break;

				case VM_CALL:
				case VM_NEW:
					code += callFunction(ra, ra_offset, code, args );
					break;

				case VM_CALLD:
					code += callFunctionDirect(ra, ra_offset, code, args );
					break;

				case VM_CALLI:
					code += callFunctionIndirect(ra, ra_offset, code, args );
					break;

				case VM_GPD:
					getPropertyDirect(ra, ra_offset, code, 0);
					code += 4;
					break;

				case VM_GPDS:
					getPropertyDirect(ra, ra_offset, code, IGNOREPROP);
					code += 4;
					break;

				case VM_SPD:
					setPropertyDirect(ra, ra_offset, code, 0);
					code += 4;
					break;

				case VM_SPDE:
					setPropertyDirect(ra, ra_offset, code, MEMBERENSURE);
					code += 4;
					break;

				case VM_SPDEH:
					setPropertyDirect(ra, ra_offset, code, MEMBERENSURE|HIDDENMEMBER);
					code += 4;
					break;

				case VM_SPDS:
					setPropertyDirect(ra, ra_offset, code, MEMBERENSURE|IGNOREPROP);
					code += 4;
					break;

				case VM_GPI:
					getPropertyIndirect(ra, ra_offset, code, 0);
					code += 4;
					break;

				case VM_GPIS:
					getPropertyIndirect(ra, ra_offset, code, IGNOREPROP);
					code += 4;
					break;

				case VM_SPI:
					setPropertyIndirect(ra, ra_offset, code, 0);
					code += 4;
					break;

				case VM_SPIE:
					setPropertyIndirect(ra, ra_offset, code, MEMBERENSURE);
					code += 4;
					break;

				case VM_SPIS:
					setPropertyIndirect(ra, ra_offset, code, MEMBERENSURE|IGNOREPROP);
					code += 4;
					break;

				case VM_GETP:
					getProperty(ra, ra_offset, code);
					code += 3;
					break;

				case VM_SETP:
					setProperty(ra, ra_offset, code);
					code += 3;
					break;

				case VM_DELD:
					deleteMemberDirect(ra, ra_offset, code);
					code += 4;
					break;

				case VM_DELI:
					deleteMemberIndirect(ra, ra_offset, code);
					code += 4;
					break;

				case VM_SRV:
					if( result != null ) result.copyRef( ra.get(ra_offset+ca.get(code+1)) );
					code += 2;
					break;

				case VM_RET:
					return code + 1;

				case VM_ENTRY:
					// TJS_FROM_VM_REG_ADDR(x) ((tjs_int)(x) / (tjs_int)sizeof(tTJSVariant))
					// TJS_FROM_VM_CODE_ADDR(x)  ((tjs_int)(x) / (tjs_int)sizeof(tjs_uint32))
					/*
					code = CodeArea + ExecuteCodeInTryBlock(ra, code-CodeArea + 3, args,
						numargs, result, TJS_FROM_VM_CODE_ADDR(code[1])+code-CodeArea,
						TJS_FROM_VM_REG_ADDR(code[2]));
					*/
					code = executeCodeInTryBlock( ra, ra_offset, code+3, args,
							result, ca.get(code+1)+code, ca.get(code+2));
					break;

				case VM_EXTRY:
					return code+1;  // same as ret

				case VM_THROW:
					throwScriptException( ra.get(ra_offset+ca.get(code+1)) ,
						mBlock, codePosToSrcPos(code) );
					code += 2; // actually here not proceed...
					break;

				case VM_CHGTHIS:
					 ra.get(ra_offset+ca.get(code+1)).changeClosureObjThis(
						 ra.get(ra_offset+ca.get(code+2)).asObject());
					code += 3;
					break;

				case VM_GLOBAL:
					ra.set( (ra_offset+ca.get(code+1)), new Variant(mBlock.getTJS().getGlobal()) );
					code += 2;
					break;

				case VM_ADDCI:
					addClassInstanceInfo(ra, ra_offset,code);
					code+=3;
					break;

				case VM_REGMEMBER:
					registerObjectMember( ra.get(ra_offset-1).asObject() );
					code ++;
					break;

				case VM_DEBUGGER:
					//TJSNativeDebuggerBreak();
					code++;
					break;

				default:
					throwInvalidVMCode();
				}
			}/*
		} catch( TJSSilentException e ) {
			throw e;
			*/
		} catch( TJSScriptException e ) {
			e.addTrace( this, codesave );
			//e.printStackTrace();
			throw e;
		} catch( TJSScriptError e ) {
			e.addTrace( this, codesave );
			//e.printStackTrace();
			throw e;
		} catch( TJSException e ) {
			displayExceptionGeneratedCode( codesave, ra_org, ra_offset );
			//TJS_eTJSScriptError( e.getMessage(), this, codesave );
			//e.printStackTrace();
			Error.reportExceptionSource( e.getMessage(), this, codePosToSrcPos(codesave) );
			throw new TJSScriptError(e.getMessage(), mBlock, codePosToSrcPos(codesave) );
		} catch( Exception e ) {
			displayExceptionGeneratedCode( codesave, ra_org, ra_offset );
			//TJS_eTJSScriptError( e.getMessage(), this, codesave );
			//e.printStackTrace();
			Error.reportExceptionSource( e.getMessage(), this, codePosToSrcPos(codesave) );
			throw new TJSScriptError(e.getMessage(), mBlock, codePosToSrcPos(codesave) );
		}

		//return codesave;
	}

	private void operateProperty(ArrayList<Variant> ra, int ra_offset, int code, int ope) throws TJSException, VariantException {
		VariantClosure clo =  ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		Variant result = new Variant();
		int hr = clo.operation(ope, null, null,
			mCodeArea.get(code+1) != 0 ? result : null,
			ra.get(ra_offset+mCodeArea.get(code+3)),
			clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
		if( hr < 0 ) throwFrom_tjs_error(hr, null);
		else {
			if( mCodeArea.get(code+1) != 0 ) {
				ra.set(ra_offset+mCodeArea.get(code+1),result);
			}
		}
	}
	private void operatePropertyIndirect(ArrayList<Variant> ra, int ra_offset, int code, int ope ) throws TJSException, VariantException {
		VariantClosure clo = ra.get(ra_offset+mCodeArea.get(code+2)).asObjectClosure();
		Variant ra_code3 = ra.get(ra_offset+mCodeArea.get(code+3));
		if( ra_code3.isInteger() != true ) {
			String str = ra_code3.asString();
			Variant result = new Variant();
			int hr = clo.operation( ope, str, null,
						mCodeArea.get(code+1)!=0 ? result : null,
						ra.get( ra_offset+mCodeArea.get(code+4)),
						clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr < 0 ) throwFrom_tjs_error( hr, str );
			ra.set( ra_offset+mCodeArea.get(code+1), result );
		} else {
			Variant result = new Variant();
			int hr = clo.operationByNum( ope, ra_code3.asInteger(),
						mCodeArea.get(code+1)!=0 ? result : null,
						ra.get( ra_offset+mCodeArea.get(code+4)),
						clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr < 0 ) throwFrom_tjs_error_num( hr, ra.get(ra_offset+mCodeArea.get(code+3)).asInteger() );
			ra.set( ra_offset+mCodeArea.get(code+1), result );
		}
	}
	private void operatePropertyDirect(ArrayList<Variant> ra, int ra_offset, int code, int ope ) throws TJSException, VariantException {
		VariantClosure clo =  ra.get( ra_offset+mCodeArea.get(code+2)).asObjectClosure();
		Variant name = mDataArea.get( mCodeArea.get(code+3) );
		String nameStr = name.getString();
		IntWrapper hint = new IntWrapper(nameStr.hashCode() );
		Variant result = new Variant();
		int hr = clo.operation(ope,
				nameStr, hint,
				mCodeArea.get(code+1) != 0 ? result : null,
				ra.get( ra_offset + mCodeArea.get(code+4)),
				clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
		if( hr < 0 )
			throwFrom_tjs_error( hr, mDataArea.get(mCodeArea.get(code+3)).getString() );
		ra.set( ra_offset+mCodeArea.get(code+1), result );
	}
	private void displayExceptionGeneratedCode(int codepos, ArrayList<Variant> ra, int ra_offset) throws VariantException {
		//TJS tjs = mBlock.getTJS();
		String info = new String( "==== An exception occured at " +
			getPositionDescriptionString(codepos) +
			", VM ip = " + String.valueOf(codepos) + " ====" );
		int info_len = info.length();

		TJS.outputToConsole( info );
		TJS.outputToConsole( "-- Disassembled VM code --" );
		disassenbleSrcLine(codepos);

		TJS.outputToConsole( "-- Register dump --" );

		final int ra_start = ra_offset - (mMaxVariableCount + mVariableReserveCount);
		int ra_count = mMaxVariableCount + mVariableReserveCount + 1 + mMaxFrameCount;
		String line = new String("");
		// if( (ra_count + ra_start) > ra.size() ) ra_count = ra.size() - ra_start;
		for( int i = 0; i < ra_count; i ++ ) {
			String reg_info = "%" + String.valueOf( i - (mMaxVariableCount + mVariableReserveCount))
				+ "=" + Utils.VariantToReadableString( ra.get( ra_start + i ) );
			if( line.length() + reg_info.length() + 2 > info_len ) {
				TJS.outputToConsole( line );
				line = reg_info;
			} else {
				if( line.length() > 0 ) line += "  ";
				line += reg_info;
			}
		}

		if( line.length() > 0 ) {
			TJS.outputToConsole( line );
		}
		/* デバッグのため追加 start TODO */
		/*
		TJS.outputToConsole( "-- Data dump --" );
		final int dataCount = mDataArea.size();
		for( int i = 0; i < dataCount; i++ ) {
			Variant v = mDataArea.get(i);
			String data_info = "*" + String.valueOf(i) + "=" +  Utils.VariantToReadableString(v);
			TJS.outputToConsole( data_info );
		}
		*/
		/* デバッグのため追加 end */
		TJS.outputToConsoleSeparator( "-", info_len );
	}
	private void disassenbleSrcLine(int codepos) throws VariantException {
		int start = findSrcLineStartCodePos(codepos);
		disassemble(start, codepos + 1);
	}
	private void disassemble(int start, int end ) throws VariantException {
		disassemble( mBlock, start, end);
	}
	private void outputFuncSrc( final String msg, final String name, int line, ScriptBlock data) {
		String buf;
		if(line >= 0)
			buf = String.format("#%s(%d) %s", name, line+1, msg );
		else
			buf = String.format("#%s %s", name, msg);

		TJS.outputToConsole(buf);
	}
	private void outputFunc( final String msg, final String comment, int addr, int codestart, int size, ScriptBlock data ) {
		String buf = String.format( "%08d %s", addr, msg );
		if( comment != null ) {
			buf += "\t// " + comment;
		}
		TJS.outputToConsole(buf);
	}
	private void dumpCodePosSrcPos() {
		final int count = mSourcePosArray.position();
		for( int i = 0; i < count; i++ ) {
			long pos = mSourcePosArray.get(i);
			String buf = String.format("code:%d,src:%d", pos>>>32, pos&0xFFFFFFFFL );
			TJS.outputToConsole(buf);
		}
	}
	public void disassemble(ScriptBlock data, int start, int end) throws VariantException {

		// dis-assemble the intermediate code.
		// "output_func" points a line output function.

		//String  s;

		String msg;
		String com;

		int prevline = -1;
		int curline = -1;

		if(end <= 0) end = mCodeArea.position();
		if(end > mCodeArea.position()) end = mCodeArea.position();

		for( int i = start; i < end; ) {
			msg = null;
			com = null;
			int size;
			int srcpos = codePosToSrcPos(i);
			int line = mBlock.srcPosToLine(srcpos);

			// output source lines as comment
			if( curline == -1 || curline <= line ) {
				if(curline == -1) curline = line;
				int nl = line - curline;
				while( curline <= line ) {
					if( nl<3 || nl >= 3 && line-curline <= 2) {
						//int len;
						String src = mBlock.getLine(curline);
						outputFuncSrc( src, "", curline, data);
						curline++;
					} else {
						curline = line - 2;
					}
				}
			} else if(prevline != line) {
				String src = mBlock.getLine(line);
				outputFuncSrc( src, "", line, data);
			}
			prevline = line;

			// decode each instructions
			switch( mCodeArea.get(i) ) {
			case VM_NOP:
				msg = "nop";
				size = 1;
				break;

			case VM_NF:
				msg = "nf";
				size = 1;
				break;

			case VM_CONST:
				msg = String.format( "const %%%d, *%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+2), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+2) ) ) );
				}
				size = 3;
				break;

				// instructions that
				// 1. have two operands that represent registers.
				// 2. do not have property access variants.
			case VM_CP:
				msg = String.format( "cp %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_CEQ:
				msg = String.format( "ceq %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_CDEQ:
				msg = String.format( "cdeq %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_CLT:
				msg = String.format( "clt %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_CGT:
				msg = String.format( "cgt %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_CHKINS:
				msg = String.format( "chkins %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;

			// instructions that
			// 1. have two operands that represent registers.
			// 2. have property access variants
			case VM_LOR:
				msg = String.format( "lor %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_LOR+1:
				msg = String.format( "lorpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_LOR+2:
				msg = String.format( "lorpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_LOR+3:
				msg = String.format( "lorp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_LAND:
				msg = String.format( "land %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_LAND+1:
				msg = String.format( "landpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_LAND+2:
				msg = String.format( "landpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_LAND+3:
				msg = String.format( "landp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_BOR:
				msg = String.format( "bor %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_BOR+1:
				msg = String.format( "borpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_BOR+2:
				msg = String.format( "borpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_BOR+3:
				msg = String.format( "borp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_BXOR:
				msg = String.format( "bxor %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_BXOR+1:
				msg = String.format( "bxorpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_BXOR+2:
				msg = String.format( "bxorpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_BXOR+3:
				msg = String.format( "bxorp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_BAND:
				msg = String.format( "band %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_BAND+1:
				msg = String.format( "bandpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_BAND+2:
				msg = String.format( "bandpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_BAND+3:
				msg = String.format( "bandp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_SAR:
				msg = String.format( "sar %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_SAR+1:
				msg = String.format( "sarpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_SAR+2:
				msg = String.format( "sarpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_SAR+3:
				msg = String.format( "sarp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_SAL:
				msg = String.format( "sal %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_SAL+1:
				msg = String.format( "salpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_SAL+2:
				msg = String.format( "salpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_SAL+3:
				msg = String.format( "salp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_SR:
				msg = String.format( "sr %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_SR+1:
				msg = String.format( "srpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_SR+2:
				msg = String.format( "srpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_SR+3:
				msg = String.format( "srp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_ADD:
				msg = String.format( "add %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_ADD+1:
				msg = String.format( "addpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_ADD+2:
				msg = String.format( "addpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_ADD+3:
				msg = String.format( "addp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_SUB:
				msg = String.format( "sub %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_SUB+1:
				msg = String.format( "subpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_SUB+2:
				msg = String.format( "subpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_SUB+3:
				msg = String.format( "subp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_MOD:
				msg = String.format( "mod %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_MOD+1:
				msg = String.format( "modpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_MOD+2:
				msg = String.format( "modpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_MOD+3:
				msg = String.format( "modp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_DIV:
				msg = String.format( "div %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_DIV+1:
				msg = String.format( "divpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_DIV+2:
				msg = String.format( "divpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_DIV+3:
				msg = String.format( "divp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_IDIV:
				msg = String.format( "idiv %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_IDIV+1:
				msg = String.format( "idivpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_IDIV+2:
				msg = String.format( "idivpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_IDIV+3:
				msg = String.format( "idivp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM
			case VM_MUL:
				msg = String.format( "mul %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;
			case VM_MUL+1:
				msg = String.format( "mulpd %%%d, %%%d.*%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				if( mDataArea != null ) {
					com = String.format("*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				size = 5;
				break;
			case VM_MUL+2:
				msg = String.format( "mulpi %%%d, %%%d.%%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3), mCodeArea.get(i+4));
				size = 5;
				break;
			case VM_MUL+3:
				msg = String.format( "mulp %%%d, %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			// OP2_DISASM

			// instructions that have one operand which represent a register,
			// except for inc, dec
			case VM_TT:			msg = String.format( "tt %%%d", mCodeArea.get(i+1) ); size = 2;		break;
			case VM_TF:			msg = String.format( "tf %%%d", mCodeArea.get(i+1) ); size = 2;		break;
			case VM_SETF:		msg = String.format( "setf %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_SETNF:		msg = String.format( "setnf %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_LNOT:		msg = String.format( "lnot %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_BNOT:		msg = String.format( "bnot %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_ASC:		msg = String.format( "asc %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_CHR:		msg = String.format( "chr %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_NUM:		msg = String.format( "num %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_CHS:		msg = String.format( "chs %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_CL:			msg = String.format( "cl %%%d", mCodeArea.get(i+1) ); size = 2;		break;
			case VM_INV:		msg = String.format( "inv %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_CHKINV:		msg = String.format( "chkinv %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_TYPEOF:		msg = String.format( "typeof %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_EVAL:		msg = String.format( "eval %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_EEXP:		msg = String.format( "eexp %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_INT:		msg = String.format( "int %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_REAL:		msg = String.format( "real %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_STR:		msg = String.format( "str %%%d", mCodeArea.get(i+1) ); size = 2;	break;
			case VM_OCTET:		msg = String.format( "octet %%%d", mCodeArea.get(i+1) ); size = 2;	break;

			case VM_CCL:
				msg = String.format( "ccl %%%d-%%%d", mCodeArea.get(i+1), mCodeArea.get(i+1) + mCodeArea.get(i+2) -1 );
				size = 3;
				break;

			// inc and dec
			case VM_INC:
				msg = String.format( "inc %%%d", mCodeArea.get(i+1) );
				size = 2;
				break;
			case VM_INC+1:
				msg = String.format("incpd %%%d, %%%d.*%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3) );
				if( mDataArea != null ) {
					com = String.format( "*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get(mCodeArea.get(i+3)) ) );
				}
				size = 4;
				break;
			case VM_INC+2:
				msg = String.format( "incpi %%%d, %%%d.%%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			case VM_INC+3:
				msg = String.format( "incp %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2));
				size = 3;
				break;
			// inc and dec
			case VM_DEC:
				msg = String.format( "dec %%%d", mCodeArea.get(i+1) );
				size = 2;
				break;
			case VM_DEC+1:
				msg = String.format( "decpd %%%d, %%%d.*%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3) );
				if( mDataArea != null ) {
					com = String.format( "*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get(mCodeArea.get(i+3)) ) );
				}
				size = 4;
				break;
			case VM_DEC+2:
				msg = String.format( "decpi %%%d, %%%d.%%%d", mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;
			case VM_DEC+3:
				msg = String.format( "decp %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2));
				size = 3;
				break;

			// instructions that have one operand which represents code area
			case VM_JF:		msg = String.format( "jf %09d", mCodeArea.get(i+1) + i); size = 2;		break;
			case VM_JNF:	msg = String.format( "jnf %09d", mCodeArea.get(i+1) + i); size = 2;		break;
			case VM_JMP:	msg = String.format( "jmp %09d", mCodeArea.get(i+1) + i); size = 2;		break;

			case VM_CALL:
			case VM_CALLD:
			case VM_CALLI:
			case VM_NEW:
			{
				// function call variants
				msg = String.format(
					mCodeArea.get(i) == VM_CALL  ? "call %%%d, %%%d(" :
					mCodeArea.get(i) == VM_CALLD ? "calld %%%d, %%%d.*%d(" :
					mCodeArea.get(i) == VM_CALLI ? "calli %%%d, %%%d.%%%d(" :
											 "new %%%d, %%%d(",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				int st; // start of arguments
				if( mCodeArea.get(i) == VM_CALLD || mCodeArea.get(i) == VM_CALLI)
					st = 5;
				else
					st = 4;
				int num = mCodeArea.get(i+st-1);     // st-1 = argument count
				boolean first = true;
				String buf = null;
				int c = 0;
				if(num == -1) {
					// omit arg
					size = st;
					msg += "...";
				} else if(num == -2) {
					// expand arg
					st++;
					num = mCodeArea.get(i+st-1);
					size = st + num * 2;
					for( int j = 0; j < num; j++ ) {
						if(!first) msg += ", ";
						first = false;
						switch(mCodeArea.get(i+st+j*2) )
						{
						case fatNormal:
							buf = String.format( "%%%d", mCodeArea.get(i+st+j*2+1) );
							break;
						case fatExpand:
							buf = String.format( "%%%d*", mCodeArea.get(i+st+j*2+1) );
							break;
						case fatUnnamedExpand:
							buf = "*";
							break;
						}
						msg += buf;
					}
				} else {
					// normal operation
					size = st + num;
					while( num > 0 ) {
						if(!first) msg += ", ";
						first = false;
						buf = String.format( "%%%d", mCodeArea.get(i+c+st) );
						c++;
						msg += buf;
						num--;
					}
				}

				msg += ")";
				if( mDataArea != null && mCodeArea.get(i) == VM_CALLD ) {
					com = String.format( "*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get( mCodeArea.get(i+3) ) ) );
				}
				break;
			}

			case VM_GPD:
			case VM_GPDS:
				// property get direct
				msg = String.format(
					mCodeArea.get(i) == VM_GPD ? "gpd %%%d, %%%d.*%d" : "gpds %%%d, %%%d.*%d",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				if( mDataArea != null ) {
					com = String.format( "*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString(mDataArea.get(mCodeArea.get(i+3))) );
				}
				size = 4;
				break;

			case VM_SPD:
			case VM_SPDE:
			case VM_SPDEH:
			case VM_SPDS:
				// property set direct
				msg = String.format(
					mCodeArea.get(i) == VM_SPD ? "spd %%%d.*%d, %%%d":
					mCodeArea.get(i) == VM_SPDE? "spde %%%d.*%d, %%%d":
					mCodeArea.get(i) == VM_SPDEH?"spdeh %%%d.*%d, %%%d":
												"spds %%%d.*%d, %%%d",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				if( mDataArea != null ) {
					com = String.format( "*%d = %s", mCodeArea.get(i+2), Utils.VariantToReadableString( mDataArea.get(mCodeArea.get(i+2))) );
				}

				size = 4;
				break;


			case VM_GPI:
			case VM_GPIS:
				// property get indirect
				msg = String.format(
					mCodeArea.get(i) == VM_GPI ?  "gpi %%%d, %%%d.%%%d":
											 "gpis %%%d, %%%d.%%%d",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;


			case VM_SPI:
			case VM_SPIE:
			case VM_SPIS:
				// property set indirect
				msg = String.format(
					mCodeArea.get(i) == VM_SPI  ?"spi %%%d.%%%d, %%%d":
					mCodeArea.get(i) == VM_SPIE ?"spie %%%d.%%%d, %%%d":
											"spis %%%d.%%%d, %%%d",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;


			case VM_SETP:
				// property set
				msg = String.format( "setp %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2));
				size = 3;
				break;

			case VM_GETP:
				// property get
				msg = String.format( "getp %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2));
				size = 3;
				break;


			case VM_DELD:
			case VM_TYPEOFD:
				// member delete direct / typeof direct
				msg = String.format(
					mCodeArea.get(i) == VM_DELD   ?"deld %%%d, %%%d.*%d":
											  "typeofd %%%d, %%%d.*%d",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				if( mDataArea != null ) {
					com= String.format( "*%d = %s", mCodeArea.get(i+3), Utils.VariantToReadableString( mDataArea.get(mCodeArea.get(i+3))));
				}
				size = 4;
				break;

			case VM_DELI:
			case VM_TYPEOFI:
				// member delete indirect / typeof indirect
				msg = String.format(
					mCodeArea.get(i) == VM_DELI ? "deli %%%d, %%%d.%%%d" : "typeofi %%%d, %%%d.%%%d",
					mCodeArea.get(i+1), mCodeArea.get(i+2), mCodeArea.get(i+3));
				size = 4;
				break;

			case VM_SRV:
				// set return value
				msg = String.format("srv %%%d", mCodeArea.get(i+1) );
				size = 2;
				break;

			case VM_RET:
				// return
				msg = "ret";
				size = 1;
				break;

			case VM_ENTRY:
				// enter try-protected block
				msg = String.format("entry %09d, %%%d", mCodeArea.get(i+1) + i, mCodeArea.get(i+2) );
				size = 3;
				break;

			case VM_EXTRY:
				// exit from try-protected block
				msg = "extry";
				size = 1;
				break;

			case VM_THROW:
				msg = String.format( "throw %%%d", mCodeArea.get(i+1) );
				size = 2;
				break;

			case VM_CHGTHIS:
				msg = String.format( "chgthis %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2));
				size = 3;
				break;

			case VM_GLOBAL:
				msg = String.format("global %%%d", mCodeArea.get(i+1));
				size = 2;
				break;

			case VM_ADDCI:
				msg = String.format("addci %%%d, %%%d", mCodeArea.get(i+1), mCodeArea.get(i+2) );
				size = 3;
				break;

			case VM_REGMEMBER:
				msg = "regmember";
				size = 1;
				break;

			case VM_DEBUGGER:
				msg = "debugger";
				size = 1;
				break;

			default:
				msg = String.format("unknown instruction %d", mCodeArea.get(i) );
				size = 1;
				break;
			} /* switch */

			outputFunc( msg, com, i, i, size, data);  // call the callback

			i+=size;
		}
	}
	private int findSrcLineStartCodePos(int codepos) {
		// find code address which is the first instruction of the source line
		if( mSourcePosArray == null ) return 0;

		int srcpos = codePosToSrcPos(codepos);
		int line = mBlock.srcPosToLine(srcpos);
		srcpos = mBlock.lineToSrcPos(line);

		int codeposmin = -1;
		final int count = mSourcePosArray.position();
		for( int i = 0; i < count; i++) {
			// 上位をcodePos, 下位をsourcePos とする
			long sourcePosArray = mSourcePosArray.get(i);
			int sourcePos = (int) ( sourcePosArray & 0xFFFFFFFFL);
			if( sourcePos >= srcpos ) {
				int codePos = (int)((sourcePosArray >> 32) & 0xFFFFFFFFL);
				if(codeposmin == -1 || codePos < codeposmin )
					codeposmin = codePos;
			}
		}
		if(codeposmin < 0) codeposmin = 0;
		return codeposmin;
	}
	static private void throwInvalidVMCode() throws TJSException {
		throw new TJSException(Error.InvalidOpecode);

	}
	private void registerObjectMember(Dispatch2 dest) throws VariantException, TJSException {
		// register this object member to 'dest' (destination object).
		// called when new object is to be created.
		// a class to receive member callback from class
		class Callback extends Dispatch {
			public Dispatch2 mDest; // destination object
			public int funcCall( int flag, final String membername, IntWrapper hint, Variant result, Variant[] param, Dispatch2 objthis) throws VariantException, TJSException {
				// *param[0] = name   *param[1] = flags   *param[2] = value
				int flags = param[1].asInteger();
				if( (flags & STATICMEMBER) == 0 ) {
					Variant val = param[2];
					if( val.isObject() ) {
						// change object's objthis if the object's objthis is null
						val.changeClosureObjThis(mDest);
					}
					if( mDest.propSetByVS( MEMBERENSURE|IGNOREPROP|flags, param[0].asString(), val, mDest) == E_NOTIMPL )
						mDest.propSet( MEMBERENSURE|IGNOREPROP|flags, param[0].getString(), null, val, mDest);
				}
				if( result != null ) result.set(1); // returns true
				return S_OK;
			}
		};

		Callback callback = new Callback();
		callback.mDest = dest;

		// enumerate members
		enumMembers( IGNOREPROP, new VariantClosure( callback, null), this);
	}
	private void addClassInstanceInfo(ArrayList<Variant> ra, int ra_offset, int code) throws VariantException {
		Dispatch2 dsp;
		dsp = ra.get( ra_offset+mCodeArea.get(code+1) ).asObject();
		if( dsp != null ) {
			dsp.classInstanceInfo( CII_ADD, 0, ra.get(ra_offset+mCodeArea.get(code+2)) );
		} else {
			// ?? must be an error
		}
	}
	private void throwScriptException( Variant val, ScriptBlock block, int srcpos ) throws TJSException, VariantException {
		String msg = null;
		if( val.isObject() ) {
			VariantClosure clo = val.asObjectClosure();
			if( clo.mObject != null ) {
				Variant v2 = new Variant();
				String message_name = "message";
				IntWrapper hint = new IntWrapper(message_name.hashCode() );
				int hr = clo.propGet( 0, message_name, hint, v2, null );
				if( hr >= 0 ) {
					msg = "script exception : " + v2.asString();
				}
			}
		}
		if(msg == null || msg.length() == 0 ) {
			msg = "script exception";
		}

		//TJSReportExceptionSource(msg, block, srcpos);
		throw new TJSScriptException(msg, block, srcpos, val);
	}
	private int codePosToSrcPos( int codepos ) {
		// converts from
		// CodeArea oriented position to source oriented position
		if( mSourcePosArray == null ) return 0;

		sortSourcePos();

		int s = 0;
		int e = mSourcePosArray.position();
		if(e==0) return 0;
		while( true ) {
			if( e-s <= 1 ) return (int) (mSourcePosArray.get(s) & 0xFFFFFFFFL);
			int m = s + (e-s)/2;
			if( (mSourcePosArray.get(m) >>> 32) > codepos)
				e = m;
			else
				s = m;
		}
	}
	private int executeCodeInTryBlock(ArrayList<Variant> ra, int ra_offset, int startip, Variant[] args, Variant result, int catchip, int exobjreg) throws VariantException, TJSException {
		// execute codes in a try-protected block
		try {
			//if( TJS.stackTracerEnabled() ) TJS.stackTracerPush(this, true);
			int ret;
			try {
				ret = executeCode( ra, ra_offset, startip, args, result );
			} finally {
				//if(TJSStackTracerEnabled()) TJSStackTracerPop();
			}
			return ret; /*
		} catch( TJSSilentException e ) {
			throw e; */
		} catch( TJSScriptException e ) {
			if( exobjreg != 0 ) ra.set(ra_offset+exobjreg, e.getValue() );
			return catchip;
		} catch( TJSScriptError e ) {
			if(exobjreg != 0) {
				Variant msg = new Variant(e.getMessage());
				Variant trace = new Variant(e.getTrace());
				Variant ret = new Variant();
				Error.getExceptionObject( mBlock.getTJS(), ret, msg, trace );
				ra.set(ra_offset+exobjreg, ret );
			}
			return catchip;
		} catch( TJSException e ) {
			if( exobjreg != 0 ){
				Variant msg = new Variant( e.getMessage() );
				Variant ret = new Variant();
				Error.getExceptionObject( mBlock.getTJS(), ret, msg, null );
				ra.set(ra_offset+exobjreg, ret );
			}
			return catchip;
		} catch( Exception e ) {
			if( exobjreg != 0 ) {
				Variant msg = new Variant( e.getMessage() );
				Variant ret = new Variant();
				Error.getExceptionObject( mBlock.getTJS(), ret, msg, null );
				ra.set(ra_offset+exobjreg, ret );
			}
			return catchip;
		}
	}
	/*
	private void getExceptionObject(TJS tjs, Variant res, Variant msg, Variant trace) throws VariantException, TJSException {
		if( res == null ) return; // not prcess

		// retrieve class "Exception" from global
		Dispatch2 global = tjs.getGlobal();
		Variant val = new Variant();
		String Exception_name = "Exception";
		IntWrapper hint = new IntWrapper( Exception_name.hashCode() );
		int hr = global.propGet( 0, Exception_name, hint, val, global );
		if( hr < 0 ) throw new TJSException( Error.ExceptionNotFound );
		// create an Exception object
		Holder<Dispatch2> excpobj = new Holder<Dispatch2>(null);
		VariantClosure clo = val.asObjectClosure();
		Variant[] pmsg = new Variant[1];
		pmsg[0] = msg;
		hr = clo.createNew(0, null, null, excpobj, pmsg, clo.mObjThis );
		if( hr < 0) throw new TJSException(Error.ExceptionNotFound);
		if( trace != null ) {
			String trace_name = "trace";
			hint.value = trace_name.hashCode();
			excpobj.mValue.propSet( MEMBERENSURE, trace_name, hint, trace, excpobj.mValue );
		}
		res.set( new Variant(excpobj.mValue, excpobj.mValue) );
	}
	*/
	private void deleteMemberIndirect(ArrayList<Variant> ra, int ra_offset, int code) throws TJSException, VariantException {
		VariantClosure clo = ra.get(ra_offset+mCodeArea.get(code+2)).asObjectClosure();
		String str = ra.get(ra_offset+mCodeArea.get(code+3)).asString();
		int hr;
		try {
			hr = clo.deleteMember( 0, str, null, clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( mCodeArea.get(code+1) != 0  ) {
				if( hr < 0 )
					ra.set(ra_offset+mCodeArea.get(code+1), new Variant(0) );
				else
					ra.set(ra_offset+mCodeArea.get(code+1), new Variant(1) );
			}
		} finally {
			str = null;
			clo = null;
		}
	}
	private void deleteMemberDirect(ArrayList<Variant> ra, int ra_offset, int code) throws TJSException, VariantException {
		VariantClosure clo = ra.get(ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		int hr;
		try {
			Variant name = mDataArea.get( mCodeArea.get(code+3) );
			String nameStr = name.getString();
			IntWrapper hint = new IntWrapper(nameStr.hashCode());
			hr = clo.deleteMember(0, nameStr, hint, ra.get(ra_offset-1).asObject() );
		} finally {
			clo = null;
		}

		if( mCodeArea.get(code+1) != 0 ) {
			if( hr < 0 )
				ra.set(ra_offset+mCodeArea.get(code+1), new Variant(0) );
			else
				ra.set(ra_offset+mCodeArea.get(code+1), new Variant(1) );
		}
	}
	private void setProperty(ArrayList<Variant> ra, int ra_offset, int code) throws TJSException, VariantException {
		VariantClosure clo = ra.get( ra_offset+mCodeArea.get(code+1) ).asObjectClosure();
		int hr;
		hr = clo.propSet(0, null, null, ra.get( ra_offset+mCodeArea.get(code+2) ),
			clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
		if( hr < 0 )
			throwFrom_tjs_error( hr, null );
	}
	static public void throwFrom_tjs_error_num( int hr, int num ) throws TJSException {
		throwFrom_tjs_error( hr, String.valueOf(num) );
	}
	static public void throwFrom_tjs_error(int hr, final String name) throws TJSException {
		// raise an exception descripted as tjs_error
		// name = variable name ( otherwide it can be NULL )
		switch( hr ) {
		case E_MEMBERNOTFOUND:
		{
			if( name != null ) {
				String str = Error.MemberNotFound.replace( "%1", name );
				throw new TJSException(str);
			} else 			{
				throw new TJSException(Error.MemberNotFoundNoNameGiven);
			}
		}
		case E_NOTIMPL:
			throw new TJSException(Error.NotImplemented);
		case E_INVALIDPARAM:
			throw new TJSException(Error.InvalidParam);
		case E_BADPARAMCOUNT:
			throw new TJSException(Error.BadParamCount);
		case E_INVALIDTYPE:
			throw new TJSException(Error.InvalidType);
		case E_ACCESSDENYED:
			throw new TJSException(Error.AccessDenyed);
		case E_INVALIDOBJECT:
			throw new TJSException(Error.InvalidObject);
		case E_NATIVECLASSCRASH:
			throw new TJSException(Error.NativeClassCrash);
		default:
			if( hr < 0 ) {
				String buf = String.format( "Unknown failure : %08X", hr );
				throw new TJSException(buf);
			}
		}
	}
	private void getProperty(ArrayList<Variant> ra, int ra_offset, int code) throws TJSException, VariantException {
		VariantClosure clo = ra.get(ra_offset+mCodeArea.get(code+2)).asObjectClosure();
		Variant result = new Variant();
		int hr = clo.propGet(0, null, null, result,
			clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
		if( hr < 0 ) throwFrom_tjs_error(hr, null);
		ra.set(ra_offset+mCodeArea.get(code+1), result );
	}
	private void setPropertyIndirect(ArrayList<Variant> ra, int ra_offset, int code, int flags ) throws TJSException, VariantException {
		Variant ra_code1 = ra.get( ra_offset + mCodeArea.get(code + 1) );
		if( ra_code1.isString() ) {
			setStringProperty( ra.get( ra_offset + mCodeArea.get(code + 3)),
				ra.get( ra_offset + mCodeArea.get(code+1)), ra.get( ra_offset + mCodeArea.get(code+2) ) );
			return;
		}
		if( ra_code1.isOctet() ) {
			setOctetProperty( ra.get( ra_offset + mCodeArea.get(code + 3)),
					ra.get( ra_offset + mCodeArea.get(code+1)), ra.get( ra_offset + mCodeArea.get(code+2) ) );
			return;
		}

		VariantClosure clo = ra_code1.asObjectClosure();
		Variant ra_code2 = ra.get( ra_offset+mCodeArea.get(code+2) );
		if( ra_code2.isInteger() ) {
			String str;
			str = ra_code2.asString();
			int hr;
			hr = clo.propSetByVS( flags,
				str, ra.get(ra_offset + mCodeArea.get(code + 3)),
					clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr == E_NOTIMPL )
				hr = clo.propSet( flags, str, null, ra.get(ra_offset + mCodeArea.get(code + 3)),
						clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr < 0 ) throwFrom_tjs_error( hr, str );
		} else {
			int hr;
			hr = clo.propSetByNum(flags, ra_code2.asInteger(), ra.get( ra_offset+ mCodeArea.get(code+3) ),
					clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr < 0 ) throwFrom_tjs_error_num( hr, ra_code2.asInteger() );
		}
	}
	private void getOctetProperty(Variant result, final Variant octet, final Variant member) throws TJSException, VariantException {
		// processes properties toward octets.
		if( member.isNumber() != true  ) {
			final String name = member.getString();
			if( name == null ) throwFrom_tjs_error( E_MEMBERNOTFOUND, "" );

			if( name.equals("length") ) {
				// get string length
				ByteBuffer o = octet.asOctet();
				if( o != null )
					result.set( o.capacity() );
				else
					result.set( 0 );
				return;
			} else if( name.charAt(0) >= '0' && name.charAt(0) <= '9' ) {
				ByteBuffer o = octet.asOctet();
				int n = Integer.valueOf( name );
				int len = o != null ? o.capacity() : 0;
				if(n<0 || n>=len)
					throw new TJSException(Error.RangeError);
				result.set( o.get(n) );
				return;
			}
			throwFrom_tjs_error( E_MEMBERNOTFOUND, name );
		} else { // member.Type() == tvtInteger || member.Type() == tvtReal
			ByteBuffer o = octet.asOctet();
			int n = member.asInteger();
			int len = o != null ? o.capacity() : 0;
			if(n<0 || n>=len)
				throw new TJSException( Error.RangeError);
			result.set( o.get(n) );
			return;
		}
	}
	private void setOctetProperty(Variant param, final Variant octet, final Variant member) throws TJSException, VariantException {
		// processes properties toward octets.
		if( member.isNumber() != true  ) {
			final String name = member.getString();
			if( name == null ) throwFrom_tjs_error( E_MEMBERNOTFOUND, "" );

			if( name.equals("length") ) {
				throwFrom_tjs_error( E_ACCESSDENYED, "" );
			} else if( name.charAt(0) >= '0' && name.charAt(0) <= '9' ) {
				throwFrom_tjs_error( E_ACCESSDENYED, "" );
			}
			throwFrom_tjs_error( E_MEMBERNOTFOUND, name );
		} else { // member.Type() == tvtInteger || member.Type() == tvtReal
			throwFrom_tjs_error( E_ACCESSDENYED, "" );
		}
	}
	private void getStringProperty(Variant result, final Variant str, final Variant member) throws TJSException, VariantException {
		// processes properties toward strings.
		if( member.isNumber() != true ) {
			final String name = member.getString();
			if( name == null ) throwFrom_tjs_error( E_MEMBERNOTFOUND, "" );

			if( name.equals("length") ) {
				// get string length
				final String s = str.asString();
				if( s == null )
					result.set(0); // tTJSVariantString::GetLength can return zero if 'this' is NULL
				else
					result.set( s.length() );
				return;
			} else if( name.charAt(0) >= '0' && name.charAt(0) <= '9' ) {
				final String s = str.asString();
				int n = Integer.valueOf(name);
				int len = s.length();
				if(n == len) { result.set( new String() ); return; }
				if(n<0 || n>len)
					throw new TJSException(Error.RangeError);

				result.set( s.substring(n,n+1) );
				return;
			}
			throwFrom_tjs_error( E_MEMBERNOTFOUND, name );
		} else { // member.Type() == tvtInteger || member.Type() == tvtReal
			final String s = str.asString();
			int n = member.asInteger();
			int len = s.length();
			if(n == len) { result.set( new String() ); return; }
			if(n<0 || n>len)
				throw new TJSException(Error.RangeError);
			result.set( s.substring(n,n+1) );
			return;
		}
	}
	private void setStringProperty(Variant param, final Variant str, final Variant member) throws TJSException, VariantException {
		// processes properties toward strings.
		if( member.isNumber() != true  ) {
			final String name = member.getString();
			if( name == null ) throwFrom_tjs_error( E_MEMBERNOTFOUND, "" );

			if( name.equals("length") ) {
				throwFrom_tjs_error( E_ACCESSDENYED, "" );
			} else if( name.charAt(0) >= '0' && name.charAt(0) <= '9' ) {
				throwFrom_tjs_error( E_ACCESSDENYED, "" );
			}
			throwFrom_tjs_error( E_MEMBERNOTFOUND, name );
		} else { // member.Type() == tvtInteger || member.Type() == tvtReal
			throwFrom_tjs_error( E_ACCESSDENYED, "" );
		}
	}
	private void getPropertyIndirect(ArrayList<Variant> ra, int ra_offset, int code, int flags ) throws TJSException, VariantException {
		Variant ra_code2 = ra.get(ra_offset+mCodeArea.get(code+2));
		if( ra_code2.isString() ) {
			Variant result = new Variant();
			getStringProperty( result, ra_code2, ra.get(ra_offset+mCodeArea.get(code+3)) );
			ra.set( ra_offset+mCodeArea.get( code + 1), result );
			return;
		}
		if( ra_code2.isOctet() ) {
			Variant result = new Variant();
			getOctetProperty( result, ra_code2, ra.get(ra_offset+mCodeArea.get(code+3)) );
			ra.set( ra_offset+mCodeArea.get( code + 1), result );
			return;
		}
		int hr;
		VariantClosure clo = ra_code2.asObjectClosure();
		Variant ra_code3 = ra.get( ra_offset + mCodeArea.get(code+3) );
		if( ra_code3.isInteger() != true  ){
			String str = ra_code3.asString();
			// OriginalTODO: verify here needs hint holding
			Variant result = new Variant();
			hr = clo.propGet(flags, str, null, result,
				clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr < 0 ) throwFrom_tjs_error( hr, str );
			ra.set( ra_offset+mCodeArea.get(code+1), result );
		} else {
			Variant result = new Variant();
			hr = clo.propGetByNum(flags, ra_code3.asInteger(), result,
				clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
			if( hr < 0 ) throwFrom_tjs_error_num( hr, ra_code3.asInteger() );
			ra.set( ra_offset+mCodeArea.get(code+1), result );
		}
	}
	private void setPropertyDirect(ArrayList<Variant> ra, int ra_offset, int code, int flags ) throws TJSException, VariantException {
		Variant ra_code1 = ra.get(ra_offset+mCodeArea.get(code+1));
		if( ra_code1.isString() ) {
			setStringProperty( ra.get( ra_offset+mCodeArea.get(code+3)), ra_code1, mDataArea.get( mCodeArea.get(code+2)) );
			return;
		}
		if( ra_code1.isOctet() ) {
			setOctetProperty( ra.get( ra_offset+mCodeArea.get(code+3)), ra_code1, mDataArea.get( mCodeArea.get(code+2)) );
			return;
		}

		int hr;
		VariantClosure clo = ra_code1.asObjectClosure();
		Variant name = mDataArea.get( mCodeArea.get(code+2));
		hr = clo.propSetByVS(flags,
			name.asString(), ra.get(ra_offset+mCodeArea.get(code+3)),
				clo.mObjThis != null ? clo.mObjThis : ra.get(ra_offset-1).asObject() );
		if( hr == E_NOTIMPL ) {
			IntWrapper hint = new IntWrapper( name.hashCode() );
			hr = clo.propSet(flags,
				name.getString(), hint, ra.get( ra_offset+mCodeArea.get(code+3)),
					clo.mObjThis != null ? clo.mObjThis : ra.get( ra_offset-1).asObject() );
		}
		if( hr < 0 )
			throwFrom_tjs_error( hr, mDataArea.get( mCodeArea.get(code+2)).getString() );

	}
	private void getPropertyDirect(ArrayList<Variant> ra, int ra_offset, int code, int flags ) throws TJSException, VariantException {
		Variant ra_code2 = ra.get( ra_offset+mCodeArea.get(code+2) );
		if( ra_code2.isString() ) {
			Variant result = new Variant();
			getStringProperty( result, ra_code2, mDataArea.get( mCodeArea.get(code+3) ) );
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			return;
		}
		if( ra_code2.isOctet() ) {
			Variant result = new Variant();
			getOctetProperty( result, ra_code2, mDataArea.get( mCodeArea.get(code+3) ));
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			return;
		}

		VariantClosure clo = ra_code2.asObjectClosure();
		Variant name = mDataArea.get( mCodeArea.get(code+3) );
		String nameStr = name.getString();
		IntWrapper hint = new IntWrapper(nameStr.hashCode());
		Variant result = new Variant();
		int hr = clo.propGet( flags, nameStr, hint, result,
				clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
		if( hr < 0 )
			throwFrom_tjs_error(hr, mDataArea.get( mCodeArea.get(code+3) ).getString());
		ra.set( ra_offset+mCodeArea.get(code+1), result );
	}
	private void processOctetFunction( final String member, final String target, Variant[] args, Variant result) throws TJSException {
		// OrigianlTODO: unpack/pack implementation
		throwFrom_tjs_error( E_MEMBERNOTFOUND, member );
	}
	private void processStringFunction( final String member, final String target, Variant[] args, Variant result) throws TJSException, VariantException {
		if( !mStrFuncInit ) initTJSStrFunc();
		if( member == null ) throwFrom_tjs_error( E_MEMBERNOTFOUND, "" );

		final int hash = member.hashCode();
		String s = new String(target); // target string
		final int s_len = target.length();
		if((hash == mStrFuncHash[StrMethod_charAt] && mStrFuncs[StrMethod_charAt].equals(member))) {
			if( args.length != 1) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
			if( s_len == 0 ) {
				if( result != null ) result.set("");
				return;
			}
			int i = args[0].asInteger();
			if( i < 0 || i >= s_len ) {
				if( result != null ) result.set("");
				return;
			}
			if(result != null) result.set( s.substring(i,i+1) );
			return;
		} else if((hash == mStrFuncHash[StrMethod_indexOf] && mStrFuncs[StrMethod_indexOf].equals(member))) {
			if( args.length != 1 && args.length != 2) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
			String pstr = args[0].asString(); // sub string
			if( s == null || pstr == null ) {
				if( result != null ) result.set( -1 );
				return;
			}
			int start;
			if( args.length == 1) {
				start = 0;
			} else {
				// integer convertion may raise an exception
				start = args[1].asInteger();
			}
			if( start >= s_len ) {
				if( result != null ) result.set( -1 );
				return;
			}
			int found = s.indexOf( pstr, start);
			if( result != null ) result.set(found);
			return;
		} else if((hash == mStrFuncHash[StrMethod_toUpperCase] && mStrFuncs[StrMethod_toUpperCase].equals(member))) {
			if( args.length != 0) throwFrom_tjs_error( E_BADPARAMCOUNT, null );
			if( result != null ) {
				result.set( s.toUpperCase() );
			}
			return;
		} else if((hash == mStrFuncHash[StrMethod_toLowerCase] && mStrFuncs[StrMethod_toLowerCase].equals(member))) {
			if( args.length != 0) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
			if( result != null ){
				result.set( s.toLowerCase() );
			}
			return;
		} else if((hash == mStrFuncHash[StrMethod_substring] && mStrFuncs[StrMethod_substring].equals(member)) || (hash == mStrFuncHash[StrMethod_substr] && mStrFuncs[StrMethod_substr].equals(member))) {
			if( args.length != 1 && args.length != 2) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
			int start = args[0].asInteger();
			if( start < 0 || start >= s_len ) {
				if( result != null ) result.set("");
				return;
			}
			int count;
			if( args.length == 2 ) {
				count = args[1].asInteger();
				if( count < 0 ) {
					if( result != null ) result.set("");
					return;
				}
				if(start + count > s_len) count = s_len - start;
				if( result != null ) result.set( s.substring( start, start+count ) );
				return;
			} else {
				if( result != null ) result.set( s.substring( start ) );
			}
			return;
		} else if((hash == mStrFuncHash[StrMethod_sprintf] && mStrFuncs[StrMethod_sprintf].equals(member))) {
			if( result != null ) {
				String res = Utils.formatString( s, args );
				result.set( res );
			}
			return;
		} else if((hash == mStrFuncHash[StrMethod_replace] && mStrFuncs[StrMethod_replace].equals(member))) {
			// string.replace(pattern, replacement-string)  -->
			// pattern.replace(string, replacement-string)
			if( args.length < 2 ) throwFrom_tjs_error(E_BADPARAMCOUNT,null);

			VariantClosure clo = args[0].asObjectClosure();
			Variant str = new Variant(target);
			Variant[] params = new Variant[2];
			params[0] = str;
			params[1] = args[1];
			final String replace_name = "replace";
			IntWrapper hint = new IntWrapper(replace_name.hashCode());
			clo.funcCall(0, replace_name, hint, result, params, null );
			return;
		} else if((hash == mStrFuncHash[StrMethod_escape] && mStrFuncs[StrMethod_escape].equals(member))) {
			if( result != null ) result.set( LexBase.escapeC(target) );
			return;
		} else if((hash == mStrFuncHash[StrMethod_split] && mStrFuncs[StrMethod_split].equals(member))) {
			// string.split(pattern, reserved, purgeempty) -->
			// Array.split(pattern, string, reserved, purgeempty)
			if( args.length < 1) throwFrom_tjs_error(E_BADPARAMCOUNT,null);

			Dispatch2 array = TJS.createArrayObject();
			try {
				Variant str = new Variant(target);
				Variant[] params;
				if( args.length >= 3 ) {
					params = new Variant[4];
					params[0] = args[0];
					params[1] = str;
					params[2] = args[1];
					params[3] = args[2];
				} else if( args.length >= 2 ) {
					params = new Variant[3];
					params[0] = args[0];
					params[1] = str;
					params[2] = args[1];
				} else {
					params = new Variant[2];
					params[0] = args[0];
					params[1] = str;
				}
				final String split_name = "split";
				IntWrapper hint = new IntWrapper(split_name.hashCode());
				array.funcCall( 0, split_name, hint, null, params, array );
				if( result != null ) result.set( new Variant(array, array) );
			} finally {
				array = null;
			}
			return;
		} else if((hash == mStrFuncHash[StrMethod_trim] && mStrFuncs[StrMethod_trim].equals(member))) {
			if( args.length != 0 ) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
			if( result == null ) return;
			result.set( s.trim() );
			return;
		} else if((hash == mStrFuncHash[StrMethod_reverse] && mStrFuncs[StrMethod_reverse].equals(member))) {
			if( args.length != 0) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
	 		if( result == null ) return;

	 		StringBuilder builder = new StringBuilder(s_len);
	 		for( int i = 0; i < s_len; i++ ) {
	 			builder.append( s.charAt(s_len-i-1) );
			}
	 		result.set( builder.toString() );
			return;
		} else if((hash == mStrFuncHash[StrMethod_repeat] && mStrFuncs[StrMethod_repeat].equals( member))) {
			if( args.length != 1) throwFrom_tjs_error(E_BADPARAMCOUNT,null);
			if( result == null ) return;
			int count = args[0].asInteger();
			if( count <= 0 || s_len <= 0 ) {
				result.set("");
				return;
			}
			final int destLength = s_len * count;
	 		StringBuilder builder = new StringBuilder(destLength);
			while( count > 0 ) {
				builder.append( s );
				count--;
			}
			result.set( builder.toString() );
			return;
		}
		throwFrom_tjs_error(E_MEMBERNOTFOUND, member);
	}
	static private void initTJSStrFunc() {
		mStrFuncInit = true;
		for( int i = 0; i < STRFUNC_MAX; i++ ) {
			mStrFuncHash[i] = mStrFuncs[i].hashCode();
		}
	}
	private Variant[] funcArgsCompact( Variant[] args, int count ) {
		if( args.length > count ) {
			Variant[] result = new Variant[count];
			System.arraycopy( args, 0, result, 0, count );
			args = null;
			return result;
		} else {
			return args;
		}
	}
	private Variant[] retrieveFuncCallArgs( ArrayList<Variant> ra, int ra_offset, int code_offset, Variant[] args ) throws VariantException, TJSException  {
		Variant[] pass_args;
		int code_size;
		int pass_args_count = mCodeArea.get( code_offset );
		if( pass_args_count == -1 ) {
			/* omitting args; pass intact aguments from the caller */
			pass_args = args;
			pass_args_count = args.length;
			code_size = 1;
		} else if(pass_args_count == -2) {
			int args_v_count = 0;
			/* count total argument count */
			pass_args_count = 0;
			int arg_written_count = mCodeArea.get( code_offset+1 );
			code_size = arg_written_count * 2 + 2;
			for( int i = 0; i < arg_written_count; i++) {
				switch( mCodeArea.get( code_offset+i*2+2 ) ) {
				case fatNormal:
					pass_args_count ++;
					break;
				case fatExpand:
					args_v_count +=
						ArrayClass.getArrayElementCount( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) ).asObject() );
					break;
				case fatUnnamedExpand:
					pass_args_count += (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
					break;
				}
			}
			pass_args_count += args_v_count;
			/* allocate temporary variant array for Array object */
			Variant[] pass_args_v = new Variant[args_v_count];
			/* allocate pointer array */
			pass_args = new Variant[pass_args_count];

			/* create pointer array to pass to callee function */
			args_v_count = 0;
			pass_args_count = 0;
			for( int i = 0; i < arg_written_count; i++ ) {
				switch( mCodeArea.get( code_offset+i*2+2 ) ) {
				case fatNormal:
					pass_args[pass_args_count++] = ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) );
					break;
				case fatExpand: {
					int count = ArrayClass.copyArrayElementTo( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2)).asObject(), pass_args_v, args_v_count, 0, -1);
					for( int j = 0; j < count; j++ ) {
						pass_args[pass_args_count++] = pass_args_v[j + args_v_count];
					}
					args_v_count += count;
					break;
				}
				case fatUnnamedExpand: {
					int count = (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
					for( int j = 0; j < count; j++ ) {
						pass_args[pass_args_count++] = args[mFuncDeclUnnamedArgArrayBase + j];
					}
					break;
				}
				}
			}
			pass_args_v = null;
		} else {
			code_size = pass_args_count + 1;
			pass_args = new Variant[pass_args_count];
			for( int i = 0; i < pass_args_count; i++)
				pass_args[i] = ra.get( ra_offset+mCodeArea.get(code_offset+1+i) );
		}

		return pass_args;
	}
	private int callFunctionIndirect(ArrayList<Variant> ra, int ra_offset, int code, Variant[] args) throws VariantException, TJSException {
		int hr;
		String name = ra.get( ra_offset+mCodeArea.get(code+3) ).asString();
		//TJS_BEGIN_FUNC_CALL_ARGS(code + 4)
		Variant[] pass_args;
		int code_size;
		try {
			final int code_offset = code + 4;
			int pass_args_count = mCodeArea.get( code_offset );
			if( pass_args_count == -1 ) {
				/* omitting args; pass intact aguments from the caller */
				pass_args = args;
				pass_args_count = args.length;
				code_size = 1;
			} else if(pass_args_count == -2) {
				int args_v_count = 0;
				/* count total argument count */
				pass_args_count = 0;
				int arg_written_count = mCodeArea.get( code_offset+1 );
				code_size = arg_written_count * 2 + 2;
				for( int i = 0; i < arg_written_count; i++) {
					switch( mCodeArea.get( code_offset+i*2+2 ) ) {
					case fatNormal:
						pass_args_count ++;
						break;
					case fatExpand:
						args_v_count +=
							ArrayClass.getArrayElementCount( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) ).asObject() );
						break;
					case fatUnnamedExpand:
						pass_args_count += (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
						break;
					}
				}
				pass_args_count += args_v_count;
				/* allocate temporary variant array for Array object */
				Variant[] pass_args_v = new Variant[args_v_count];
				/* allocate pointer array */
				pass_args = new Variant[pass_args_count];

				/* create pointer array to pass to callee function */
				args_v_count = 0;
				pass_args_count = 0;
				for( int i = 0; i < arg_written_count; i++ ) {
					switch( mCodeArea.get( code_offset+i*2+2 ) ) {
					case fatNormal:
						pass_args[pass_args_count++] = ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) );
						break;
					case fatExpand: {
						int count = ArrayClass.copyArrayElementTo( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2)).asObject(), pass_args_v, args_v_count, 0, -1);
						for( int j = 0; j < count; j++ ) {
							pass_args[pass_args_count++] = pass_args_v[j + args_v_count];
						}
						args_v_count += count;
						break;
					}
					case fatUnnamedExpand: {
						int count = (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
						for( int j = 0; j < count; j++ ) {
							pass_args[pass_args_count++] = args[mFuncDeclUnnamedArgArrayBase + j];
						}
						break;
					}
					}
				}
				pass_args_v = null;
			} else {
				code_size = pass_args_count + 1;
				pass_args = new Variant[pass_args_count];
				for( int i = 0; i < pass_args_count; i++)
					pass_args[i] = ra.get( ra_offset+mCodeArea.get(code_offset+1+i) );
			}
			//TJS_BEGIN_FUNC_CALL_ARGS(code + 4)

			Variant t = ra.get( ra_offset+mCodeArea.get(code+2) );
			if( t.isString() ) {
				Variant result = new Variant();
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				processStringFunction( name, ra.get( ra_offset+mCodeArea.get(code+2) ).asString(),
					pass_args, mCodeArea.get(code+1) != 0 ? result:null);
				if( mCodeArea.get(code+1) != 0 ) {
					ra.set( ra_offset+mCodeArea.get(code+1), result );
				}
				hr = S_OK;
			} else if( t.isOctet() ) {
				Variant result = new Variant();
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				processOctetFunction( name, ra.get( ra_offset+mCodeArea.get(code+2) ).asString(),
					pass_args, mCodeArea.get(code+1) != 0 ? result:null);
				if( mCodeArea.get(code+1) != 0 ) {
					ra.set( ra_offset+mCodeArea.get(code+1), result );
				}
				hr = S_OK;
			} else {
				VariantClosure clo =  ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
				IntWrapper hint = new IntWrapper(name.hashCode());
				Variant result = new Variant();
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				hr = clo.funcCall(0, name, hint, mCodeArea.get(code+1) != 0 ? result : null,
						pass_args, clo.mObjThis != null ? clo.mObjThis:ra.get( ra_offset-1 ).asObject());
				if( mCodeArea.get(code+1) != 0 ) {
					ra.set( ra_offset+mCodeArea.get(code+1), result );
				}
			}
		} finally {
			pass_args = null;
		}

		if( hr < 0 ) throwFrom_tjs_error( hr, name );

		return code_size + 4;
	}
	private int callFunctionDirect(ArrayList<Variant> ra, int ra_offset, int code, Variant[] args) throws TJSException, VariantException {
		int hr;
		//TJS_BEGIN_FUNC_CALL_ARGS(code + 4)
		Variant[] pass_args;
		//Variant[] pass_args_p = new Variant[PASS_ARGS_PREPARED_ARRAY_COUNT];
		//Variant[] pass_args_v = null;
		int code_size;
		try {
			final int code_offset = code + 4;
			int pass_args_count = mCodeArea.get( code_offset );
			if( pass_args_count == -1 ) {
				/* omitting args; pass intact aguments from the caller */
				pass_args = args;
				pass_args_count = args.length;
				code_size = 1;
			} else if(pass_args_count == -2) {
				int args_v_count = 0;
				/* count total argument count */
				pass_args_count = 0;
				int arg_written_count = mCodeArea.get( code_offset+1 );
				code_size = arg_written_count * 2 + 2;
				for( int i = 0; i < arg_written_count; i++) {
					switch( mCodeArea.get( code_offset+i*2+2 ) ) {
					case fatNormal:
						pass_args_count ++;
						break;
					case fatExpand:
						args_v_count +=
							ArrayClass.getArrayElementCount( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) ).asObject() );
						break;
					case fatUnnamedExpand:
						pass_args_count += (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
						break;
					}
				}
				pass_args_count += args_v_count;
				/* allocate temporary variant array for Array object */
				Variant[] pass_args_v = new Variant[args_v_count];
				/* allocate pointer array */
				pass_args = new Variant[pass_args_count];

				/* create pointer array to pass to callee function */
				args_v_count = 0;
				pass_args_count = 0;
				for( int i = 0; i < arg_written_count; i++ ) {
					switch( mCodeArea.get( code_offset+i*2+2 ) ) {
					case fatNormal:
						pass_args[pass_args_count++] = ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) );
						break;
					case fatExpand: {
						int count = ArrayClass.copyArrayElementTo( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2)).asObject(), pass_args_v, args_v_count, 0, -1);
						for( int j = 0; j < count; j++ ) {
							pass_args[pass_args_count++] = pass_args_v[j + args_v_count];
						}
						args_v_count += count;
						break;
					}
					case fatUnnamedExpand: {
						int count = (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
						for( int j = 0; j < count; j++ ) {
							pass_args[pass_args_count++] = args[mFuncDeclUnnamedArgArrayBase + j];
						}
						break;
					}
					}
				}
				pass_args_v = null;
			} else {
				code_size = pass_args_count + 1;
				pass_args = new Variant[pass_args_count];
				for( int i = 0; i < pass_args_count; i++)
					pass_args[i] = ra.get( ra_offset+mCodeArea.get(code_offset+1+i) );
			}
			//TJS_BEGIN_FUNC_CALL_ARGS(code + 4)

			Variant t = ra.get( ra_offset+mCodeArea.get(code+2) );
			Variant name = mDataArea.get( mCodeArea.get(code+3) );
			if( t.isString() ) {
				Variant result = new Variant();
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				processStringFunction( name.getString(),
					ra.get( ra_offset+mCodeArea.get(code+2) ).asString(),
					pass_args, mCodeArea.get(code+1) != 0 ? result:null);
				if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
				hr = S_OK;
			} else if( t.isOctet() ) {
				Variant result = new Variant();
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				processOctetFunction( name.getString(),
					ra.get( ra_offset+mCodeArea.get(code+2) ).asString(),
					pass_args, mCodeArea.get(code+1) != 0 ? result:null);
				if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
				hr = S_OK;
			} else {
				VariantClosure clo =  ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
				String nameStr = name.getString();
				IntWrapper hint = new IntWrapper( nameStr.hashCode() );
				Variant result = new Variant();
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				hr = clo.funcCall(0, nameStr, hint, mCodeArea.get(code+1) != 0 ? result:null,
						pass_args, clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
				if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
			}
		} finally {
			pass_args = null;
		}

		if( hr < 0 ) throwFrom_tjs_error( hr, mDataArea.get( mCodeArea.get(code+3) ).asString() );

		return code_size + 4;
	}
	private int callFunction(ArrayList<Variant> ra, int ra_offset, int code, Variant[] args) throws TJSException, VariantException {
		// function calling / create new object
		int hr;
		//TJS_BEGIN_FUNC_CALL_ARGS(code + 3)
		Variant[] pass_args;
		int code_size;
		try {
			final int code_offset = code + 3;
			int pass_args_count = mCodeArea.get( code_offset );
			if( pass_args_count == -1 ) {
				/* omitting args; pass intact aguments from the caller */
				pass_args = args;
				pass_args_count = args.length;
				code_size = 1;
			} else if(pass_args_count == -2) {
				int args_v_count = 0;
				/* count total argument count */
				pass_args_count = 0;
				int arg_written_count = mCodeArea.get( code_offset+1 );
				code_size = arg_written_count * 2 + 2;
				for( int i = 0; i < arg_written_count; i++) {
					switch( mCodeArea.get( code_offset+i*2+2 ) ) {
					case fatNormal:
						pass_args_count ++;
						break;
					case fatExpand:
						args_v_count +=
							ArrayClass.getArrayElementCount( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) ).asObject() );
						break;
					case fatUnnamedExpand:
						pass_args_count += (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
						break;
					}
				}
				pass_args_count += args_v_count;
				/* allocate temporary variant array for Array object */
				Variant[] pass_args_v = new Variant[args_v_count];
				/* allocate pointer array */
				pass_args = new Variant[pass_args_count];

				/* create pointer array to pass to callee function */
				args_v_count = 0;
				pass_args_count = 0;
				for( int i = 0; i < arg_written_count; i++ ) {
					switch( mCodeArea.get( code_offset+i*2+2 ) ) {
					case fatNormal:
						pass_args[pass_args_count++] = ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2 ) );
						break;
					case fatExpand: {
						int count = ArrayClass.copyArrayElementTo( ra.get( ra_offset+mCodeArea.get( code_offset+i*2+1+2)).asObject(), pass_args_v, args_v_count, 0, -1);
						for( int j = 0; j < count; j++ ) {
							pass_args[pass_args_count++] = pass_args_v[j + args_v_count];
						}
						args_v_count += count;
						break;
					}
					case fatUnnamedExpand: {
						int count = (args.length > mFuncDeclUnnamedArgArrayBase) ? (args.length - mFuncDeclUnnamedArgArrayBase) : 0;
						for( int j = 0; j < count; j++ ) {
							pass_args[pass_args_count++] = args[mFuncDeclUnnamedArgArrayBase + j];
						}
						break;
					}
					}
				}
				pass_args_v = null;
			} else {
				code_size = pass_args_count + 1;
				pass_args = new Variant[pass_args_count];
				for( int i = 0; i < pass_args_count; i++)
					pass_args[i] = ra.get( ra_offset+mCodeArea.get(code_offset+1+i) );
			}
			//TJS_BEGIN_FUNC_CALL_ARGS(code + 3)

			VariantClosure clo = ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
			if( mCodeArea.get(code+0) == VM_CALL ) {
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				Variant result = new Variant();
				hr = clo.funcCall(0, null, null,
					mCodeArea.get(code+1) != 0 ? result :null, pass_args,
						clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
				if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
			}
			else
			{
				//if( pass_args.length != pass_args_count ) pass_args = funcArgsCompact( pass_args, pass_args_count );
				Holder<Dispatch2> dsp = new Holder<Dispatch2>(null);
				hr = clo.createNew(0, null, null, dsp, pass_args,
						clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
				if( hr >= 0 ) {
					if( dsp.mValue != null  ) {
						if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), new Variant(dsp.mValue, dsp.mValue) );
					}
				}
			}
			// OriginalTODO: Null Check
		} finally {
			pass_args = null;
		}

		if( hr < 0 ) throwFrom_tjs_error(hr, "" );

		return code_size + 3;
	}
	private void instanceOf( final Variant name, Variant targ) throws VariantException, TJSException {
		// checks instance inheritance.
		String str = name.asString();
		if( str != null ) {
			int hr = CustomObject.defaultIsInstanceOf(0, targ, str, null);
			if( hr < 0 ) throwFrom_tjs_error(hr,null);

			targ.set( (hr == S_TRUE) ? 1 : 0 );
			return;
		}
		targ.set(0);
	}
	private void eval(Variant val, Dispatch2 objthis, boolean resneed) throws VariantException, TJSException, CompileException {
		Variant res = new Variant();
		String str = val.asString();
		if( str.length() > 0 ) {
			if( resneed )
				mBlock.getTJS().evalExpression( str, res, objthis, null, 0 );
			else
				mBlock.getTJS().evalExpression( str, null, objthis, null, 0);
		}
		if(resneed) val.set( res );
	}
	private void typeOfMemberIndirect(ArrayList<Variant> ra, int ra_offset, int code, int flags) throws TJSException, VariantException {
		Variant t = ra.get( ra_offset+mCodeArea.get(code+2) );
		if( t.isString() ) {
			Variant result = new Variant();
			getStringProperty( result,
				ra.get( ra_offset+mCodeArea.get(code+2) ),
				ra.get( ra_offset+mCodeArea.get(code+3) ));
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			typeOf(ra.get( ra_offset+mCodeArea.get(code+1)) );
			return;
		} if( t.isOctet()) {
			Variant result = new Variant();
			getOctetProperty( result,
				ra.get( ra_offset+mCodeArea.get(code+2) ),
				ra.get( ra_offset+mCodeArea.get(code+3) ));
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			typeOf(ra.get( ra_offset+mCodeArea.get(code+1) ));
			return;
		}

		int hr;
		VariantClosure clo = ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		if( ra.get( ra_offset+mCodeArea.get(code+3) ).isInteger() != true ) {
			String str = ra.get( ra_offset+mCodeArea.get(code+3) ).asString();
			// OriginalTODO: verify here needs hint holding
			Variant result = new Variant();
			hr = clo.propGet( flags, str, null, result,
				clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			if( hr == S_OK ) {
				typeOf( ra.get( ra_offset+mCodeArea.get(code+1) ) );
			} else if( hr == E_MEMBERNOTFOUND ) {
				ra.set( ra_offset+mCodeArea.get(code+1), new Variant("undefined") );
			} else if( hr < 0 ) throwFrom_tjs_error(hr, str);
		} else {
			Variant result = new Variant();
			hr = clo.propGetByNum(flags, ra.get( ra_offset+mCodeArea.get(code+3) ).asInteger(), result,
				clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			if( hr == S_OK ) {
				typeOf( ra.get( ra_offset+mCodeArea.get(code+1) ) );
			} else if( hr == E_MEMBERNOTFOUND ) {
				ra.set( ra_offset+mCodeArea.get(code+1), new Variant("undefined") );
			} else if( hr < 0 ) throwFrom_tjs_error_num( hr, ra.get( ra_offset+mCodeArea.get(code+3) ).asInteger() );
		}
	}
	private void typeOfMemberDirect(ArrayList<Variant> ra, int ra_offset, int code, int flags) throws TJSException, VariantException {
		Variant t = ra.get( ra_offset+mCodeArea.get(code+2) );
		if( t.isString() ) {
			Variant result = new Variant();
			getStringProperty( result, ra.get( ra_offset+mCodeArea.get(code+2) ), mDataArea.get( mCodeArea.get(code+3) ) );
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			typeOf( ra.get( ra_offset+mCodeArea.get(code+1) ));
			return;
		} if( t.isOctet() ){
			Variant result = new Variant();
			getOctetProperty( result, ra.get( ra_offset+mCodeArea.get(code+2) ), mDataArea.get( mCodeArea.get(code+3) ));
			ra.set( ra_offset+mCodeArea.get(code+1), result );
			typeOf(ra.get( ra_offset+mCodeArea.get(code+1) ));
			return;
		}

		int hr;
		VariantClosure clo = ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		Variant name = mDataArea.get( mCodeArea.get(code+3) );
		String nameStr = name.getString();
		IntWrapper hint = new IntWrapper(nameStr.hashCode());
		Variant result = new Variant();
		hr = clo.propGet(flags, name.getString(), hint, result,
					clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
		ra.set( ra_offset+mCodeArea.get(code+1), result );
		if( hr == S_OK ) {
			typeOf(ra.get( ra_offset+mCodeArea.get(code+1) ));
		} else if( hr == E_MEMBERNOTFOUND ) {
			ra.set( ra_offset+mCodeArea.get(code+1), new Variant("undefined") );
		} else if( hr < 0 ) throwFrom_tjs_error(hr, mDataArea.get( mCodeArea.get(code+3) ).getString());
	}
	private void typeOf( Variant val ) {
		// processes TJS2's typeof operator.
		String name = val.getTypeName();
		if( name != null ) {
			val.set( name );
		}
	}
	private void operateProperty0(ArrayList<Variant> ra, int ra_offset, int code, int ope) throws TJSException, VariantException {
		VariantClosure clo =  ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		Variant result = new Variant();
		int hr = clo.operation(ope, null, null,
				mCodeArea.get(code+1) != 0 ? result : null, null,
				clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
		if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
		if( hr < 0 ) throwFrom_tjs_error(hr, null);
	}
	private void operatePropertyIndirect0(ArrayList<Variant> ra, int ra_offset, int code, int ope ) throws TJSException, VariantException {
		VariantClosure clo = ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		Variant ra_code3 = ra.get( ra_offset+mCodeArea.get(code+3) );
		if( ra_code3.isInteger() != true ) {
			String str = ra_code3.asString();
			Variant result = new Variant();
			int hr = clo.operation(ope, str, null, mCodeArea.get(code+1) != 0 ? result:null, null,
					clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
			if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
			if( hr < 0 ) throwFrom_tjs_error(hr, str);
		} else {
			Variant result = new Variant();
			int hr = clo.operationByNum(ope, ra.get( ra_offset+mCodeArea.get(code+3) ).asInteger(),
					mCodeArea.get(code+1) != 0 ? result:null, null,
					clo.mObjThis != null ?clo.mObjThis:ra.get( ra_offset-1 ).asObject());
			if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
			if( hr < 0 ) throwFrom_tjs_error_num(hr, ra.get( ra_offset+mCodeArea.get(code+3) ).asInteger());
		}
	}
	private void operatePropertyDirect0(ArrayList<Variant> ra, int ra_offset, int code, int ope) throws TJSException, VariantException {
		VariantClosure clo = ra.get( ra_offset+mCodeArea.get(code+2) ).asObjectClosure();
		Variant name = mDataArea.get( mCodeArea.get(code+3) );
		String nameStr = name.getString();
		IntWrapper hint = new IntWrapper(nameStr.hashCode());
		Variant result = new Variant();
		int hr = clo.operation( ope, nameStr, hint, mCodeArea.get(code+1) != 0 ? result:null, null,
				ra.get( ra_offset-1 ).asObject());
		if( mCodeArea.get(code+1) != 0 ) ra.set( ra_offset+mCodeArea.get(code+1), result );
		if( hr < 0 ) throwFrom_tjs_error( hr, mDataArea.get( mCodeArea.get(code+3) ).getString() );
	}
	private void continuousClear(ArrayList<Variant> ra, int ra_offset, int code) {
		int start = ra_offset+mCodeArea.get(code+1);
		int end = start+mCodeArea.get(code+2);
		while( start < end ) {
			ra.get(start).clear();
			start++;
		}
	}
	public String getPositionDescriptionString(int codepos) {
		return mBlock.getLineDescriptionString( codePosToSrcPos(codepos) ) + "[" + getShortDescription() + "]";
	}
	private String getShortDescription() {
		String ret = "(" + getContextTypeName() + ")";
		String name;
		if( mContextType == ContextType.PROPERTY_SETTER || mContextType == ContextType.PROPERTY_GETTER) {
			if( mParent != null )
				name = mParent.mName;
			else
				name = null;
		} else {
			name = mName;
		}
		if( name != null ) ret += " " + name;
		return ret;
	}
	public String getContextTypeName() {
		switch(mContextType)
		{
		case ContextType.TOP_LEVEL:				return "top level script";
		case ContextType.FUNCTION:				return "function";
		case ContextType.EXPR_FUNCTION:			return "function expression";
		case ContextType.PROPERTY:				return "property";
		case ContextType.PROPERTY_SETTER:		return "property setter";
		case ContextType.PROPERTY_GETTER:		return "property getter";
		case ContextType.CLASS:					return "class";
		case ContextType.SUPER_CLASS_GETTER:	return "super class getter proxy";
		default:								return "unknown";
		}
	}
	// Dispatch2 implementation
	// function invocation
	public int funcCall( int flag, final String membername, IntWrapper hint, Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		if( !getValidity() )
			return E_INVALIDOBJECT;

		if( membername == null ) {
			switch( mContextType ) {
			case ContextType.TOP_LEVEL:
				executeAsFunction( objthis != null ? objthis : mBlock.getTJS().getGlobal(), null, result, 0);
				break;

			case ContextType.FUNCTION:
			case ContextType.EXPR_FUNCTION:
			case ContextType.PROPERTY_GETTER:
			case ContextType.PROPERTY_SETTER:
				executeAsFunction( objthis, param, result, 0 );
				break;

			case ContextType.CLASS: // on super class' initialization
				executeAsFunction( objthis, param, result, 0 );
				break;

			case ContextType.PROPERTY:
				return E_INVALIDTYPE;
			}

			return S_OK;
		}

		int hr = super.funcCall( flag, membername, hint, result, param, objthis);

		if( membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count > 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i-- ) {
					Integer v = pointer.get(i);
					mSuperClassGetter.executeAsFunction( null, null, res, v.intValue() );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.funcCall(flag, membername, hint, result, param, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// property get
	public int propGet( int flag, final String membername, IntWrapper hint, Variant result, Dispatch2 objthis ) throws VariantException, TJSException {
		if( !getValidity() ) return E_INVALIDOBJECT;

		if( membername == null ) {
			if( mContextType == ContextType.PROPERTY ) {
				// executed as a property getter
				if( mPropGetter != null )
					return mPropGetter.funcCall(0, null, null, result, null, objthis);
				else
					return E_ACCESSDENYED;
			}
		}

		int hr = super.propGet(flag, membername, hint, result, objthis);

		if( membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.propGet(flag, membername, hint, result, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// property set
	public int propSet( int flag, String membername, IntWrapper hint, final Variant param, Dispatch2 objthis ) throws VariantException, TJSException {
		if( !getValidity() ) return E_INVALIDOBJECT;

		if( membername == null ) {
			if( mContextType == ContextType.PROPERTY ) {
				// executed as a property setter
				if( mPropSetter != null ) {
					Variant[] params = new Variant[1];
					params[0] = param;
					return mPropSetter.funcCall(0, null, null, null, params, objthis );
				} else
					return E_ACCESSDENYED;

					// WARNING!! const tTJSVariant ** -> tTJSVariant** force casting
			}
		}

		int hr;
		if( membername != null && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			int pseudo_flag = (flag & IGNOREPROP) != 0 ? flag : (flag &~ MEMBERENSURE);
			// member ensuring is temporarily disabled unless IGNOREPROP
			hr = super.propSet(pseudo_flag, membername, hint, param,objthis);
			if(hr == E_MEMBERNOTFOUND) {
				ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
				final int count = pointer.size();
				if( count != 0 ) {
					Variant res = new Variant();
					for( int i = count-1; i >= 0; i--) {
						mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
						VariantClosure clo = res.asObjectClosure();
						hr = clo.propSet(pseudo_flag, membername, hint, param, objthis);
						if( hr != E_MEMBERNOTFOUND ) break;
					}
				}
			}

			if( hr == E_MEMBERNOTFOUND && (flag & MEMBERENSURE) != 0 ) {
				// re-ensure the member for "this" object
				hr = super.propSet(flag, membername, hint, param, objthis);
			}
		} else {
			hr = super.propSet(flag, membername, hint, param, objthis);
		}
		return hr;
	}

	// create new object
	public int createNew( int flag, String membername, IntWrapper hint, Holder<Dispatch2> result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		if( !getValidity() ) return E_INVALIDOBJECT;

		if( membername == null ) {
			if( mContextType != ContextType.CLASS ) return E_INVALIDTYPE;

			Dispatch2 dsp = new CustomObject();

			executeAsFunction(dsp, null, null, 0);
			funcCall(0, mName, null, null, param, dsp);
			result.set( dsp );
			return S_OK;
		}

		int hr = super.createNew(flag, membername, hint, result, param, objthis);

		if( membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.createNew(flag, membername, hint, result, param, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// class instance matching returns false or true
	public int isInstanceOf( int flag, String membername, IntWrapper hint, String classname, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity()) return E_INVALIDOBJECT;

		if( membername == null ) {
			switch(mContextType)
			{
			case ContextType.TOP_LEVEL:
			case ContextType.PROPERTY_SETTER:
			case ContextType.PROPERTY_GETTER:
			case ContextType.SUPER_CLASS_GETTER:
				break;

			case ContextType.FUNCTION:
			case ContextType.EXPR_FUNCTION:
				if( "Function".equals(classname) ) return S_TRUE;
				break;

			case ContextType.PROPERTY:
				if( "Property".equals(classname) ) return S_TRUE;
				break;

			case ContextType.CLASS:
				if( "Class".equals(classname) ) return S_TRUE;
				break;
			}
		}

		int hr = super.isInstanceOf(flag, membername, hint, classname, objthis);

		if( membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.isInstanceOf(flag, membername, hint, classname, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// get member count
	public int getCount( IntWrapper result, final String membername, IntWrapper hint, Dispatch2 objthis ) throws VariantException, TJSException {
		int hr = super.getCount(result, membername, hint, objthis);

		if(membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null )
		{
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.getCount(result, membername, hint, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// property for internal use
	public int propSetByVS( int flag, String membername, final Variant param, Dispatch2 objthis ) throws VariantException, TJSException {
		return E_NOTIMPL;
	}

	// delete member
	public int deleteMember( int flag, String membername, IntWrapper hint, Dispatch2 objthis ) throws VariantException, TJSException {
		int hr = super.deleteMember(flag, membername, hint, objthis);

		if(membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.deleteMember(flag, membername, hint, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// invalidation
	public int invalidate( int flag, String membername, IntWrapper hint, Dispatch2 objthis ) throws VariantException, TJSException {
		int hr = super.invalidate(flag, membername, hint, objthis);

		if( membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.invalidate(flag, membername, hint, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// get validation, returns true or false
	public int isValid( int flag, String membername, IntWrapper hint, Dispatch2 objthis ) throws VariantException, TJSException {
		int hr = super.isValid(flag, membername, hint, objthis);

		if(membername != null && hr == E_MEMBERNOTFOUND && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			// look up super class
			ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
			final int count = pointer.size();
			if( count != 0 ) {
				Variant res = new Variant();
				for( int i = count-1; i >= 0; i--) {
					mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
					VariantClosure clo = res.asObjectClosure();
					hr = clo.isValid(flag, membername, hint, objthis);
					if( hr != E_MEMBERNOTFOUND ) break;
				}
			}
		}
		return hr;
	}

	// operation with member
	public int operation( int flag, String membername, IntWrapper hint, Variant result, final Variant param, Dispatch2 objthis ) throws VariantException, TJSException {
		if(membername == null) {
			if( mContextType == ContextType.PROPERTY ) {
				// operation for property object
				return super.dispatchOperation(flag, membername, hint, result, param, objthis);
			} else {
				return super.operation(flag, membername, hint, result, param, objthis);
			}
		}

		int hr;
		if( membername != null && mContextType == ContextType.CLASS && mSuperClassGetter != null ) {
			int pseudo_flag = (flag & IGNOREPROP) !=  0 ? flag : (flag &~ MEMBERENSURE);
			hr = super.operation(pseudo_flag, membername, hint, result, param, objthis);
			if( hr == E_MEMBERNOTFOUND ) {
				// look up super class
				ArrayList<Integer> pointer = mSuperClassGetter.mSuperClassGetterPointer;
				final int count = pointer.size();
				if( count != 0 ) {
					Variant res = new Variant();
					for( int i = count-1; i >= 0; i--) {
						mSuperClassGetter.executeAsFunction( null, null, res, pointer.get(i) );
						VariantClosure clo = res.asObjectClosure();
						hr = clo.operation(pseudo_flag, membername, hint, result, param,
						objthis);
						if( hr != E_MEMBERNOTFOUND ) break;
					}
				}
			}
			if(hr == E_MEMBERNOTFOUND) hr = super.operation(flag, membername, hint, result, param, objthis);
			return hr;
		} else {
			return super.operation(flag, membername, hint, result, param, objthis);
		}
	}

	// VMCodes
	private static final int
		VM_NOP		= 0,
		VM_CONST	= 1,
		VM_CP		= 2,
		VM_CL		= 3,
		VM_CCL		= 4,
		VM_TT		= 5,
		VM_TF		= 6,
		VM_CEQ		= 7,
		VM_CDEQ		= 8,
		VM_CLT		= 9,
		VM_CGT		= 10,
		VM_SETF		= 11,
		VM_SETNF	= 12,
		VM_LNOT		= 13,
		VM_NF		= 14,
		VM_JF		= 15,
		VM_JNF		= 16,
		VM_JMP		= 17,

		VM_INC		= 18,
		VM_INCPD	= 19,
		VM_INCPI	= 20,
		VM_INCP		= 21,
		VM_DEC		= 22,
		VM_DECPD	= 23,
		VM_DECPI	= 24,
		VM_DECP		= 25,
		VM_LOR		= 26,
		VM_LORPD	= 27,
		VM_LORPI	= 28,
		VM_LORP		= 29,
		VM_LAND		= 30,
		VM_LANDPD	= 31,
		VM_LANDPI	= 32,
		VM_LANDP	= 33,
		VM_BOR		= 34,
		VM_BORPD	= 35,
		VM_BORPI	= 36,
		VM_BORP		= 37,
		VM_BXOR		= 38,
		VM_BXORPD	= 39,
		VM_BXORPI	= 40,
		VM_BXORP	= 41,
		VM_BAND		= 42,
		VM_BANDPD	= 43,
		VM_BANDPI	= 44,
		VM_BANDP	= 45,
		VM_SAR		= 46,
		VM_SARPD	= 47,
		VM_SARPI	= 48,
		VM_SARP		= 49,
		VM_SAL		= 50,
		VM_SALPD	= 51,
		VM_SALPI	= 52,
		VM_SALP		= 53,
		VM_SR		= 54,
		VM_SRPD		= 55,
		VM_SRPI		= 56,
		VM_SRP		= 57,
		VM_ADD		= 58,
		VM_ADDPD	= 59,
		VM_ADDPI	= 60,
		VM_ADDP		= 61,
		VM_SUB		= 62,
		VM_SUBPD	= 63,
		VM_SUBPI	= 64,
		VM_SUBP		= 65,
		VM_MOD		= 66,
		VM_MODPD	= 67,
		VM_MODPI	= 68,
		VM_MODP		= 69,
		VM_DIV		= 70,
		VM_DIVPD	= 71,
		VM_DIVPI	= 72,
		VM_DIVP		= 73,
		VM_IDIV		= 74,
		VM_IDIVPD	= 75,
		VM_IDIVPI	= 76,
		VM_IDIVP	= 77,
		VM_MUL		= 78,
		VM_MULPD	= 79,
		VM_MULPI	= 80,
		VM_MULP		= 81,

		VM_BNOT		= 82,
		VM_TYPEOF	= 83,
		VM_TYPEOFD	= 84,
		VM_TYPEOFI	= 85,
		VM_EVAL		= 86,
		VM_EEXP		= 87,
		VM_CHKINS	= 88,
		VM_ASC		= 89,
		VM_CHR		= 90,
		VM_NUM		= 91,
		VM_CHS		= 92,
		VM_INV		= 93,
		VM_CHKINV	= 94,
		VM_INT		= 95,
		VM_REAL		= 96,
		VM_STR		= 97,
		VM_OCTET	= 98,
		VM_CALL		= 99,
		VM_CALLD	= 100,
		VM_CALLI	= 101,
		VM_NEW		= 102,
		VM_GPD		= 103,
		VM_SPD		= 104,
		VM_SPDE		= 105,
		VM_SPDEH	= 106,
		VM_GPI		= 107,
		VM_SPI		= 108,
		VM_SPIE		= 109,
		VM_GPDS		= 110,
		VM_SPDS		= 111,
		VM_GPIS		= 112,
		VM_SPIS		= 113,
		VM_SETP		= 114,
		VM_GETP		= 115,
		VM_DELD		= 116,
		VM_DELI		= 117,
		VM_SRV		= 118,
		VM_RET		= 119,
		VM_ENTRY	= 120,
		VM_EXTRY	= 121,
		VM_THROW	= 122,
		VM_CHGTHIS	= 123,
		VM_GLOBAL	= 124,
		VM_ADDCI	= 125,
		VM_REGMEMBER= 126,
		VM_DEBUGGER	= 127,
		__VM_LAST	= 128;
	// SubType
	static private final int
		stNone		=VM_NOP,
		stEqual		=VM_CP,
		stBitAND	=VM_BAND,
		stBitOR		=VM_BOR,
		stBitXOR	=VM_BXOR,
		stSub		=VM_SUB,
		stAdd		=VM_ADD,
		stMod		=VM_MOD,
		stDiv		=VM_DIV,
		stIDiv		=VM_IDIV,
		stMul		=VM_MUL,
		stLogOR		=VM_LOR,
		stLogAND	=VM_LAND,
		stSAR		=VM_SAR,
		stSAL		=VM_SAL,
		stSR		=VM_SR,

		stPreInc	= __VM_LAST,
		stPreDec	=129,
		stPostInc	=130,
		stPostDec	=131,
		stDelete	=132,
		stFuncCall	=133,
		stIgnorePropGet	=134,
		stIgnorePropSet	=135,
		stTypeOf	=136;
	// FuncArgType
	static private final int
		fatNormal = 0,
		fatExpand = 1,
		fatUnnamedExpand = 2;

	static private final int
		OP_BAND	= 0x0001,
		OP_BOR	= 0x0002,
		OP_BXOR	= 0x0003,
		OP_SUB	= 0x0004,
		OP_ADD	= 0x0005,
		OP_MOD	= 0x0006,
		OP_DIV	= 0x0007,
		OP_IDIV	= 0x0008,
		OP_MUL	= 0x0009,
		OP_LOR	= 0x000a,
		OP_LAND	= 0x000b,
		OP_SAR	= 0x000c,
		OP_SAL	= 0x000d,
		OP_SR	= 0x000e,
		OP_INC	= 0x000f,
		OP_DEC	= 0x0010,
		OP_MASK	= 0x001f,
		OP_MIN	= OP_BAND,
		OP_MAX	= OP_DEC;

	static private final int RT_NEEDED = 0x0001;   // result needed
	static private final int RT_CFLAG = 0x0002;   // condition flag needed
	static private final int GNC_CFLAG = (1<<(4*8-1)); // true logic
	static private final int GNC_CFLAG_I = (GNC_CFLAG+1); // inverted logic
	//static private final int TJS_MEMBERENSURE = 0x00000200; // create a member if not exists
	//static private final int TJS_IGNOREPROP = 0x00000800; // ignore property invoking
	public int getCodeSize() { return mCodeArea.position(); }
	public int getDataSize() { return mDataArea.size(); }
}
