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.
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.
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.
The TJS2 VM has only one flag and stores the comparison result. Flags take only true or false values.
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.
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).
Do nothing.
Format: const %dest, *src
dest.CopyRef(src);
Copy the value of the constant area indicated by *src
to the register indicated by %dest
.
Format: cp %dest, %src
dest.CopyRef(src);
Copies the value of the register pointed to by %src
to the register pointed to by %dest
.
Format: cl %dest
dest.Clear();
Makes the register indicated by %dest
void.
Format: ccl %low-%high
Makes all registers from %low
to %high
void.
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.
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.
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.
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.
Format: clt %reg1, %reg2
flag = reg1.GreaterThan(reg2); // no, this is not a mistake
Set the flag to true if %reg1
> %reg2
, false otherwise.
Format: cgt %reg1, %reg2
flag = reg1.LittlerThan(reg2); // no, this is not a mistake
Set the flag to true if %reg1
< %reg2
, false otherwise.
Format: setf %dest
dest = flag;
Set %dest
to true (integer non-zero) if flag is true, false (integer 0) if false.
Format: setnf %dest
dest = !flag;
Conversely to setf, sets %dest
to true (integer 0) if flag is false, false (integer 0) if true.
Format: lnot %reg
reg.logicalnot();
Reverses the truth of %reg
.
Format: nf
flag = !flag;
Reverse the truth of the flag.
Format: jf ip
if (flag)
goto ip;
If the flag is true, jump to ip.
Format: jnf ip
if (!flag)
goto ip;
If the flag is false, jump to ip.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Format: bnot %reg
reg.bitnot();
Invert %reg bitwise and store it again in %reg.
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.
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.
Format: num %reg
reg.tonumber();
Converts the register represented by %reg to a number.
Format: chs %reg
reg.changesign();
Reverses the sign of the number in the register represented by %reg.
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.
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.
Format: int %reg
reg.ToInteger();
Converts the register represented by %reg to an integer.
Format: real %reg
reg.ToReal();
Converts the register represented by %reg to a real number.
Format: string %reg
reg.ToString();
Converts the register represented by %reg to a string.
Format: octet %reg
reg.ToOctet();
Converts the register represented by %reg to an octet sequence.
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.
Format: eval %reg
Executes the string represented by %reg as an expression and stores the result in %reg again.
Format: eexp %reg
Executes the string represented by %reg as an expression and discards the result.
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;
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).
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.
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.
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.
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.
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.
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.
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.
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.
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).
Format: ret
Return to caller.
Format: entry ip, %reg
Enter an exception-protected block. If an exception occurs, jump to ip and set the exception object to %reg.
Format: extry
Exit from an exception-protected block.
Format: throw %reg
Throws the object represented by %reg as an exception object.
Format: chgthis %dest, %src
dest.ChangeClosureObjThis(src.AsObjectNoAddRef());
Changes the closure part of the object represented by %dest to the object represented by %src.
Format: global %dest
dest = Block->GetTJS()->GetGlobalNoAddRef();
Store the global object in %dest.
Format: addci %dest, %info
Add %info to the class instance information of the object represented by %dest.
Format: regmember
Register a member of the class with the "this" object. Used internally.
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.