Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Last active May 1, 2023 15:59
Show Gist options
  • Save uyjulian/1433ac019acaa6f3582a44efaadfb5bf to your computer and use it in GitHub Desktop.
Save uyjulian/1433ac019acaa6f3582a44efaadfb5bf to your computer and use it in GitHub Desktop.

TJS2 VM

TJS2 compiles the script into binary code for the virtual machine (TJS2 VM) and then executes it.
A brief description of this virtual machine is provided, as the disassembly result of this TJS2 VM code is displayed when an exception occurs or when a dump is taken.

Instruction code

The TJS2 VM is independent for each execution unit such as functions and properties, and one function does not share the instruction code space, register space, flags, and constant area with other functions.
The instruction pointer (ip) always starts from 0 at the head of a function or the like.
A mnemonic is a simple human-readable name for an instruction code.

register

TJS2 VM registers are represented by %(number) in the mnemonic. Numbers can be negative. There is no limit on the number of registers. All local variables and temporary values during calculation are recorded in registers. There is no main memory or stack.
The values represented by the registers are the same as so-called variables in TJS2, and can represent integers, real numbers, objects, strings, octets, and voids.
In the current version, register %0 is always void. Register %-1 becomes this. Register %-2 is a special object called this proxy. When a member reference is made to this object, the operation that looks at this first, and if not there, goes to global. To do. this proxy does not exist in the global level execution unit. The execution of the function and other arguments is started in a state where they are stored in advance in registers such as %-3 and %-4.
The values of registers other than those whose uses are predetermined or whose values are stored before execution are undefined at the start of execution.

flag

The TJS2 VM has only one flag and stores the comparison result. Flags take only true or false values.

Constant area

The constant area of the TJS2 VM is a place to store constants, and is represented by *(number) in the mnemonic. The constant area is read-only, and the const instruction is used to transfer the value of this constant area to the register. In addition, the "name" for accessing the member of the object by name, such as function name and property name, is also stored in this constant area.

VM mnemonic list

Some operands have the form %obj.*name or %obj.%name, but these involve object member references.
Operands that have the form %obj.*name are direct references, and the object represented by the register %obj refers to the member whose name is represented by *name.
Operands that have the form %obj.%name perform indirect references, and use the register from the object represented by the register %obj, refers to the member whose name is represented by %name.
The mnemonics for such instructions have the suffix d or pd (direct / property direct) or i or pi (indirect / property indirect).
Anything with a suffix of p runs the property handler for the target register (works for the unary '*' operator).

nop - no operation

Do nothing.

const - copy constant value

Format: const %dest, *src

dest.CopyRef(src);

Copy the value of the constant area indicated by *src to the register indicated by %dest.

cp - copy register

Format: cp %dest, %src

dest.CopyRef(src);

Copies the value of the register pointed to by %src to the register pointed to by %dest.

cl - clear register

Format: cl %dest

dest.Clear();

Makes the register indicated by %dest void.

ccl - clear register

Format: ccl %low-%high
Makes all registers from %low to %high void.

tt - test true

Format: tt %reg

flag = reg.operator bool();

Sets the flag to true if the register indicated by %reg indicates true, and sets the flag to false if it indicates false.

tf - test false

Format: tf %reg

flag = !(reg.operator bool());

Conversely to tt, set the flag to false if the register pointed to by %reg indicates true, and set the flag to true if it indicates false.

ceq - compare equal

Format: ceq %reg1, %reg2

flag = reg1.NormalCompare(reg2);

Set the flag to true if %reg1 and %reg2 match in a normal comparison (the behavior of the == operator), otherwise false.

cdeq - compare distinct equal

Format: cdeq %reg1, %reg2

flag = reg1.DiscernCompare(reg2);

Set the flag to true if %reg1 and %reg2 match in an identity comparison (the behavior of the === operator), otherwise set the flag to false.

clt - compare littler than

Format: clt %reg1, %reg2

flag = reg1.GreaterThan(reg2); // no, this is not a mistake

Set the flag to true if %reg1 > %reg2, false otherwise.

cgt - compare greater than

Format: cgt %reg1, %reg2

flag = reg1.LittlerThan(reg2); // no, this is not a mistake

Set the flag to true if %reg1 < %reg2, false otherwise.

setf - set flag

Format: setf %dest

dest = flag;

Set %dest to true (integer non-zero) if flag is true, false (integer 0) if false.

setnf - set not flag

Format: setnf %dest

dest = !flag;

Conversely to setf, sets %dest to true (integer 0) if flag is false, false (integer 0) if true.

lnot - logical not

Format: lnot %reg

reg.logicalnot();

Reverses the truth of %reg.

nf - not flag

Format: nf

flag = !flag;

Reverse the truth of the flag.

jf - jump if flag

Format: jf ip

if (flag)
	goto ip;

If the flag is true, jump to ip.

jnf - jump if not flag

Format: jnf ip

if (!flag)
	goto ip;

If the flag is false, jump to ip.

inc, incpd, incpi, incp - increment

Format: inc %reg

reg.increment();

Format: incpd %res, %obj.*name
Format: incpi %res, %obj.%name
Format: incp %res, %propobj

Increments %reg or %obj.*name or %obj.%name or %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

dec, decpd, decpi, decp - decrement

Format: dec %reg

reg.decrement();

Format: decpd %res, %obj.*name
Format: decpi %res, %obj.%name
Format: decp %res, %propobj

Decrement %reg or %obj.*name or %obj.%name or %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

lor, lorpd, lorpi, lorp - logical or

Format: lor %dest, %src

dest.logicalorequal(src);

Performs a logical OR of %dest and %src and stores the result in %dest.
Format: lorpd %res, %obj.*name, %src
Performs a logical OR of %obj.*name and %src and stores the result in %obj.*name.
Format: lorpi %res, %obj.%name, %src
Performs a logical OR of %obj.%name and %src and stores the result in %obj.%name.
Format: lorp %res, %propobj, %src
Performs a logical OR of %propobj and %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

land, landpd, landpi, landp - logical and

Format: land %dest, %src

dest.logicalandequal(src);

Performs a logical AND of %dest and %src and stores the result in %dest.
Format: landpd %res, %obj.*name, %src
Performs a logical AND of %obj.*name and %src and stores the result in %obj.*name.
Format: landpi %res, %obj.%name, %src
Performs a logical AND of %obj.%name and %src and stores the result in %obj.%name.
Format: landp %res, %propobj, %src
Performs a logical AND of %propobj and %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

bor, borpd, borpi, borp - bitwise or

Format: bor %dest, %src

dest.operator |=(src);

Performs a bitwise OR of %dest and %src and stores the result in %dest.
Format: borpd %res, %obj.*name, %src
Performs a bitwise OR of %obj.*name and %src and stores the result in %obj.*name.
Format: borpi %res, %obj.%name, %src
Performs a bitwise OR of %obj.%name and %src and stores the result in %obj.%name.
Format: borp %res, %propobj, %src
Performs a bitwise OR of %propobj and %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

bxor, bxorpd, bxorpi, bxorp - bitwise xor

Format: bxor %dest, %src

dest.operator ^=(src);

Performs a bitwise exclusive OR of %dest and %src and stores the result in %dest.
Format: bxorpd %res, %obj.*name, %src
Performs a bitwise exclusive OR of %obj.*name and %src and stores the result in %obj.*name.
Format: bxorpi %res, %obj.%name, %src
Performs a bitwise exclusive OR of %obj.%name and %src and stores the result in %obj.%name.
Format: bxorp %res, %propobj, %src
Performs a bitwise exclusive OR of %propobj and %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

band, bandpd, bandpi, bandp - bitwise and

Format: band %dest, %src

dest.operator &=(src);

Performs a bitwise AND of %dest and %src and stores the result in %dest.
Format: bandpd %res, %obj.*name, %src
Performs a bitwise AND of %obj.*name and %src and stores the result in %obj.*name.
Format: bandpi %res, %obj.%name, %src
Performs a bitwise AND of %obj.%name and %src and stores the result in %obj.%name.
Format: bandp %res, %propobj, %src
Performs a bitwise AND of %propobj and %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

sar, sarpd, sarpi, sarp - shift arithmetic right

Format: sar %dest, %src

dest.operator >>=(src);

%dest is arithmetically shifted right by the number of times represented by %src, and the result is stored in %dest.
Format: sarpd %res, %obj.*name, %src
The result of arithmetic right shift of %obj.*name by the number of times represented by %src is stored in %obj.*name.
Format: sarpi %res, %obj.%name, %src
The result of arithmetic right shift of %obj.%name by the number of times represented by %src is stored in %obj.%name.
Format: sarp %res, %propobj, %src
%propobj is arithmetically shifted right by the number of times represented by %src, and the result is stored in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

sal, salpd, salpi, salp - shift arithmetic left

Format: sal %dest, %src

dest.operator <<=(src);

%dest is arithmetically shifted left by the number of times represented by %src, and the result is stored in %dest.
Format: salpd %res, %obj.*name, %src
The result of arithmetic left shift of %obj.*name by the number of times represented by %src is stored in %obj.*name.
Format: salpi %res, %obj.%name, %src
Store the result of arithmetic left shift of %obj.%name by the number of times represented by %src in %obj.%name.
Format: salp %res, %propobj, %src
%propobj is shifted left by the number of times represented by %src, and the result is stored in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

sr, srpd, srpi, srp - shift bitwise right

Format: sr %dest, %src

dest.rbitshiftequal(src);

%dest is shifted to the right by the number of times represented by %src, and the result is stored in %dest.
Format: srpd %res, %obj.*name, %src
%obj.*name is shifted to the right by the number of times represented by %src, and the result is stored in %obj.*name.
Format: srpi %res, %obj.%name, %src
%obj.%name is shifted right by the number of times represented by %src, and the result is stored in %obj.%name.
Format: srp %res, %propobj, %src
%propobj is shifted right by the number of times represented by %src, and the result is stored in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

add, addpd, addpi, addp - add

Format add %dest, %src

dest.operator +=(src);

Add %src to %dest and store the result in %dest.
Format addpd %res, %obj.*name, %src
Add %src to %obj.*name and store the result in %obj.*name.
Format addpi %res, %obj.%name, %src
Add %src to %obj.%name and store the result in %obj.%name.
Format addp %res, %propobj, %src
Add %src to %propobj and store the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

sub, subpd, subpi, subp - subtract

Format: sub %dest, %src

dest.operator -=(src);

Subtract %src from %dest and stores the result in %dest.
Format: subpd %res, %obj.*name, %src
Subtract %src from %obj.*name and store the result in %obj.*name.
Format: subpi %res, %obj.%name, %src
Subtract %src from %obj.%name and store the result in %obj.%name.
Format: subp %res, %propobj, %src
Subtracts %src from %propobj and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

mod, modpd, modpi, modp - modulo

Format: mod %dest, %src

dest.operator %=(src);

Store the remainder of %dest divided by %src in %dest.
Format: modpd %res, %obj.*name, %src
Store the remainder of %obj.*name divided by %src in %obj.*name.
Format: modpi %res, %obj.%name, %src
Store the remainder of %obj.%name divided by %src in %obj.%name.
Format: modp %res, %propobj, %src
Store the remainder of %propobj divided by %src in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

div, divpd, divpi, divp - real divide

Format: div %dest, %src

dest.operator /=(src);

Divide %dest by real number by %src and stores the result in %dest.
Format: divpd %res, %obj.*name, %src
Divide %obj.*name by real number by %src and store the result in %obj.*name.
Format: divpi %res, %obj.%name, %src
Divide %obj.*name by real number by %src and store the result in %obj.*name.
Format: divp %res, %propobj, %src
Divide %propobj by real number by %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

idiv, idivpd, idivpi, idivp - integer divide

Format: idiv %dest, %src

dest.idivequal(src);

Divide %dest by %src by integer and store the result in %dest.
Format: idivpd %res, %obj.*name, %src
Divide %obj.*name by %src by integer and store the result in %obj.*name.
Format: idivpi %res, %obj.%name, %src
Divide %obj.%name by %src by integer and store the result in %obj.%name.
Format: divp %res, %propobj, %src
Divide %propobj by %src and store the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

mul, mulpd, mulpi, mulp - multiply

Format: mul %dest, %src

dest.operator *=(src);

Multiplies %dest by %src and stores the result in %dest.
Format: mulpd %res, %obj.*name, %src
Multiplies %obj.*name by %src and stores the result in %obj.*name.
Format: mulpi %res, %obj.%name, %src
Multiplies %obj.%name by %src and stores the result in %obj.%name.
Format: mulp %res, %propobj, %src
Multiplies %propobj by %src and stores the result in %propobj.
Among the above instructions, those with %res as a parameter will also store the result in %res if res is not 0.

bnot - bitwise not

Format: bnot %reg

reg.bitnot();

Invert %reg bitwise and store it again in %reg.

asc - make ascii string

Format: asc %reg

tTJSVariantString * str = reg.AsString();
if(str)
{
	const tjs_char *ch = (const tjs_char*)*str;
	reg = tTVInteger(ch[0]);
	str->Release();
	return;
}
reg = tTVInteger(0);

Creates one character corresponding to the number represented by %reg and stores it again in %reg.

chr - cheracter code

Format: chr %reg

tjs_char ch[2];
ch[0] = static_cast<tjs_char>(reg.AsInteger());
ch[1] = 0;
reg = ch;

Store the character code of the first character of the character string represented by %reg in %reg.

num - number

Format: num %reg

reg.tonumber();

Converts the register represented by %reg to a number.

chs - change sign

Format: chs %reg

reg.changesign();

Reverses the sign of the number in the register represented by %reg.

inv - invalidate

Format: inv %reg

reg = reg.Type() != tvtObject ? false : (reg.AsObjectClosureNoAddRef().Invalidate(0, NULL, NULL, ra[-1].AsObjectNoAddRef()) == TJS_S_TRUE);

Invalidates the object represented by %reg.

chkinv - invalidate

Format: chkinv %reg

reg = reg.Type() != tvtObject ? true : TJSIsObjectValid(reg.AsObjectClosureNoAddRef().IsValid(0, NULL, NULL, ra[-1].AsObjectNoAddRef()));

Set %reg to true if the object represented by %reg has not been invalidated; otherwise, set it to false.

int - convert to integer

Format: int %reg

reg.ToInteger();

Converts the register represented by %reg to an integer.

real - convert to real

Format: real %reg

reg.ToReal();

Converts the register represented by %reg to a real number.

string - convert to string

Format: string %reg

reg.ToString();

Converts the register represented by %reg to a string.

octet - convert to octet

Format: octet %reg

reg.ToOctet();

Converts the register represented by %reg to an octet sequence.

typeof, typeofd, typeofi - check type

Format: typeof %reg

static tTJSString void_name(TJS_W("void"));
static tTJSString Object_name(TJS_W("Object"));
static tTJSString String_name(TJS_W("String"));
static tTJSString Integer_name(TJS_W("Integer"));
static tTJSString Real_name(TJS_W("Real"));
static tTJSString Octet_name(TJS_W("Octet"));

switch(reg.Type())
{
case tvtVoid:
	reg = void_name;   // differs from TJS1
	break;

case tvtObject:
	reg = Object_name;
	break;

case tvtString:
	reg = String_name;
	break;

case tvtInteger:
	reg = Integer_name; // differs from TJS1
	break;

case tvtReal:
	reg = Real_name; // differs from TJS1
	break;

case tvtOctet:
	reg = Octet_name;
	break;
}

Format: typeofd %obj.*name
Format: typeofi %obj.%name

Examine the type of %reg or %obj.*name or %obj.%name and store the string representing that type in %reg or %obj.*name or %obj.%name again.

eval - evaluate expression

Format: eval %reg
Executes the string represented by %reg as an expression and stores the result in %reg again.

eexp - execute expression

Format: eexp %reg
Executes the string represented by %reg as an expression and discards the result.

chkins - check instance

Format: chkins %reg, %classname
If the object represented by %reg is an instance of the class with the class name represented by %classname, store true in %reg, otherwise store false.

// checks instance inheritance.
tTJSVariantString *str = classname.AsString();
if(str)
{
	tjs_error hr;
	try
	{
		hr = TJSDefaultIsInstanceOf(0, reg, (const tjs_char*)*str, NULL);
	}
	catch(...)
	{
		str->Release();
		throw;
	}
	str->Release();
	if(TJS_FAILED(hr)) TJSThrowFrom_tjs_error(hr);

	reg = (hr == TJS_S_TRUE);
	return;
}
reg = false;

call, calld, calli - function call

Format: call %dest, %func(%arg1, %arg2, %arg3, ...)
Format: calld %dest, %obj.*name(%arg1, %arg2, %arg3, ...)
Format: calli %dest, %obj.%name(%arg1, %arg2, %arg3, ...)

Calls the function object represented by %func or %obj.*name or %obj.%name with the arguments %arg1,%arg2,%arg3 ... and stores the result in %dest. If %dest is %0, the result is discarded (not stored in %0).

new - create new

Format: new %dest, %func(%arg1, %arg2, %arg3, ...)
Constructs a class object represented by %func with the arguments %arg1, %arg2, %arg3 ... and stores the result in %dest.

gpd, gpds - get property direct

Format: gpd %dest, %obj.*name
Format: gpds %dest, %obj.*name

Reference the member represented by *name from the object represented by %obj and copy its value to %dest.
gpd involves calling a property handler, but gpds does not call the property handler and gets the property object itself.

gpi, gpis - get property indirect

Format: gpi %dest, %obj.%name
Format: gpis %dest, %obj.%name

References the member represented by %name from the object represented by %obj and copies its value to %dest.
gpi involves calling a property handler, but gpis does not call a property handler and gets the property object itself.

spd, spde, spdeh, spds - set property direct

Format: spd %obj.*name
Format: spde %obj.*name
Format: spdeh %obj.*name
Format: spds %obj.*name

Assign the value of %src to the member represented by *name of the object represented by %obj.
spd performs normal access, but raises an exception if the member does not exist.
spde creates a new member if it does not exist.
spdeh sets the member as a hidden member. It has no meaning in the current version.
spds does not call the property handler and replaces the property object itself.

spi, spie, spis - set property indirect

Format: spi %obj.%name
Format: spie %obj.%name
Format: spis %obj.%name

Assign the value of %src to the member represented by %name of the object represented by %obj.
spi performs normal access, but raises an exception if the member does not exist.
spie creates a new member if it does not exist.
spis does not call the property handler and replaces the property object itself.

getp

Format: getp %reg, %propobj

Operate the property object getter represented by %propobj to get the property value and assign it to %reg. Performs the operation of the unary '*' operator.

setp

Format: setp %propobj, %reg

Operate the setter of the property object represented by %propobj and set the value of %reg. Performs the operation of the unary '*' operator.

deld, deli - delete member

Format: deld %reg, %obj.*name
Format: deli %reg, %obj.%name

Deletes the member represented by *name or %name of the object represented by %obj.
Stores whether the deletion was successful or not in %reg, but discards the result if %reg is %0.

srv - set result value

Format: srv %reg

if(result) result->CopyRef(reg);

Returns the value of %reg as the return value of the function (the return value of the function is the value represented by %reg).

ret - return

Format: ret
Return to caller.

entry - enter try block

Format: entry ip, %reg
Enter an exception-protected block. If an exception occurs, jump to ip and set the exception object to %reg.

extry - exit from try block

Format: extry
Exit from an exception-protected block.

throw - throw exception object

Format: throw %reg
Throws the object represented by %reg as an exception object.

chgthis - change this

Format: chgthis %dest, %src

dest.ChangeClosureObjThis(src.AsObjectNoAddRef());

Changes the closure part of the object represented by %dest to the object represented by %src.

global - get global object

Format: global %dest

dest = Block->GetTJS()->GetGlobalNoAddRef();

Store the global object in %dest.

addci - add class instance information

Format: addci %dest, %info
Add %info to the class instance information of the object represented by %dest.

regmember - register members

Format: regmember
Register a member of the class with the "this" object. Used internally.

debugger - call debugger

Format: debugger

#ifdef ENABLE_DEBUGGER
				if( is_enable_debugger ) {
					TJSDebuggerHook( DBGHOOK_PREV_BREAK, Block->GetName(), cur_line_no, this );
					cur_line_no = -1;
				}
#else	// ENABLE_DEBUGGER
				TJSNativeDebuggerBreak();
#endif	// ENABLE_DEBUGGER

Suspend execution and invoke the debugger. The current version of the implementation calls the native debugger instead of the TJS2 debugger.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment