"
COPYRIGHT (c) 1996-2011 by Claus Gittinger
COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
SWING Research Group, Czech Technical University in Prague
Parts of the code written by Claus Gittinger are under following
license:
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
Parts of the code written at SWING Reasearch Group [1] are MIT licensed:
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the 'Software'), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
[1] Code written at SWING Research Group contain a signature
of one of the above copright owners.
"
"{ Package: 'stx:libjava' }"
JavaByteCodeProcessor subclass:#JavaByteCodeInterpreter
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category:'Languages-Java-Bytecode'
!
!JavaByteCodeInterpreter class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1996-2011 by Claus Gittinger
COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
SWING Research Group, Czech Technical University in Prague
Parts of the code written by Claus Gittinger are under following
license:
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
Parts of the code written at SWING Reasearch Group [1] are MIT licensed:
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the 'Software'), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
[1] Code written at SWING Research Group contain a signature
of one of the above copright owners.
"
!
documentation
"
Base class for intepreting Java bytecode.
This class is based on NewCompiler::JavaByteCodeInterpreter
written originally by Claus Gittinger
[author:]
Jan Vrany (jan.vrany@fit.cvut.cz)
[instance variables:]
[class variables:]
[see also:]
"
! !
!JavaByteCodeInterpreter class methodsFor:'interpretation'!
interpret:aMethod receiver:aReceiver arguments:argArray
^ self new interpret:aMethod receiver:aReceiver arguments:argArray
! !
!JavaByteCodeInterpreter methodsFor:'instructions'!
aaload
"loads onto the stack a reference from an array
stack: arrayref, index -> value
args: nothing"
| arrayref index |
index := self pop.
arrayref := self pop.
arrayref ifNil: [ ^ JavaVM throwNullPointerException ].
^ self pushRef: (arrayref at: index + 1).
"
The arrayref must be of type reference and must refer to an array whose
components are of type reference. The index must be of type int. Both arrayref
and index are popped from the operand stack. The reference value in the component
of the array at index is retrieved and pushed onto the operand stack.
If arrayref is null, aaload throws a NullPointerException.
Otherwise, if index is not within the bounds of the array referenced by arrayref,
the aaload instruction throws an ArrayIndexOutOfBoundsException."
"Modified: / 16-03-2011 / 15:27:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 21-03-2011 / 17:20:46 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
aastore
"stores into a reference in an array
stack: arrayref, index, value -> nothing
args: nothing"
| arrayref index value |
value := self pop.
index := self pop.
arrayref := self pop.
arrayref ifNil: [ ^ JavaVM throwNullPointerException ].
arrayref at: index + 1 put: value.
"
The arrayref must be of type reference and must refer to an array whose components are of
type reference. The index must be of type int and value must be of type reference. The arrayref,
index, and value are popped from the operand stack. The reference value is stored as the
component of the array at index.
The type of value must be assignment compatible (§2.6.7) with the type of the components
of the array referenced by arrayref. Assignment of a value of reference type S (source)
to a variable of reference type T (target) is allowed only when the type S supports all
the operations defined on type T. The detailed rules follow:
If S is a class type, then:
If T is a class type, then S must be the same class (§2.8.1) as T, or S must be a subclass of T;
If T is an interface type, S must implement (§2.13) interface T.
If S is an interface type, then:
If T is a class type, then T must be Object (§2.4.7).
If T is an interface type, then T must be the same interface as S or a superinterface of S (§2.13.2).
If S is an array type, namely, the type SC[], that is, an array of components of type SC, then:
If T is a class type, then T must be Object (§2.4.7).
If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true:
TC and SC are the same primitive type (§2.4.1).
TC and SC are reference types (§2.4.6), and type SC is assignable to TC by these runtime rules.
If T is an interface type, T must be one of the interfaces implemented by arrays (§2.15).
If arrayref is null, aastore throws a NullPointerException.
Otherwise, if index is not within the bounds of the array referenced by arrayref,
the aastore instruction throws an ArrayIndexOutOfBoundsException.
Otherwise, if arrayref is not null and the actual type of value is not assignment
compatible (§2.6.7) with the actual type of the components of the array, aastore
throws an ArrayStoreException."
"Modified: / 22-03-2011 / 12:27:17 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
aconst_null
"
Push null
stack: nothing -> null
args: nothing"
self pushConstant: nil.
"
Description
Push the null object reference onto the operand stack.
Notes
The Java virtual machine does not mandate a concrete
value for null."
"Created: / 24-02-2011 / 22:40:50 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 24-02-2011 / 22:07:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 14-03-2011 / 20:55:27 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
aload
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
aload: idx
"Load reference from local variable
nothing -> objectRef
args: index"
self pushRef: (context at: idx + 1).
"Description
The index is an unsigned byte that must be an index into the local
variable array of the current frame (§3.6). The local variable at
index must contain a reference. The objectref in the local variable
at index is pushed onto the operand stack.
Notes
The aload instruction cannot be used to load a value of type returnAddress
from a local variable onto the operand stack. This asymmetry with the
astore instruction is intentional.
The aload opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index."
"Modified: / 13-03-2011 / 20:59:08 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
anewarray
"
Create new array of reference
stack: count -> arrayRef
args: arrayType"
| type size |
type := constantPool at: self fetchIndex2.
size := self pop.
self pushNewArrayOf: type sized: size.
"
Description
The count must be of type int. It is popped off the operand stack. The count
represents the number of components of the array to be created. The unsigned
indexbyte1 and indexbyte2 are used to construct an index into the runtime
constant pool of the current class (§3.6), where the value of the index is
(indexbyte1 << 8) | indexbyte2. The runtime constant pool item at that index
must be a symbolic reference to a class, array, or interface type. The named
class, array, or interface type is resolved (§5.4.3.1). A new array with components
of that type, of length count, is allocated from the garbage-collected heap,
and a reference arrayref to this new array object is pushed onto the operand
stack. All components of the new array are initialized to null, the default
value for reference types (§2.5.1).
Linking Exceptions
During resolution of the symbolic reference to the class, array, or interface
type, any of the exceptions documented in §5.4.3.1 can be thrown.
Runtime Exception
Otherwise, if count is less than zero, the anewarray instruction throws a
NegativeArraySizeException.
Notes
The anewarray instruction is used to create a single dimension of an array of
object references or part of a multidimensional array."
"Created: / 14-03-2011 / 18:24:57 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 27-03-2011 / 21:12:45 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
areturn
"
Return reference from method
stack: objectRef -> empty
args: nothing"
self leaveProcessorWith: (self pop).
"
Description
The objectref must be of type reference and must refer to an object of a type
that is assignment compatible (§2.6.7) with the type represented by the return
descriptor (§4.3.3) of the current method. If the current method is a synchronized
method, the monitor acquired or reentered on invocation of the method is released
or exited (respectively) as if by execution of a monitorexit instruction. If no
exception is thrown, objectref is popped from the operand stack of the current
frame (§3.6) and pushed onto the operand stack of the frame of the invoker. Any
other values on the operand stack of the current method are discarded.
The interpreter then reinstates the frame of the invoker and returns control to
the invoker.
Runtime Exceptions
If the current method is a synchronized method and the current thread is not the
owner of the monitor acquired or reentered on invocation of the method, areturn
throws an IllegalMonitorStateException. This can happen, for example, if a synchronized
method contains a monitorexit instruction, but no monitorenter instruction, on the object
on which the method is synchronized.
Otherwise, if the virtual machine implementation enforces the rules on structured use
of locks described in §8.13 and if the first of those rules is violated during invocation
of the current method, then areturn throws an IllegalMonitorStateException."
"Created: / 14-03-2011 / 13:45:29 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
arraylength
"
Get length of array
stack: arrayRef -> length
args: nothing"
self pushInt: self pop size.
"
Description
The arrayref must be of type reference and must refer to an array. It is
popped from the operand stack. The length of the array it references is
determined. That length is pushed onto the operand stack as an int.
Runtime Exception
If the arrayref is null, the arraylength instruction throws a NullPointerException."
"Created: / 14-03-2011 / 18:41:01 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
astore
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
astore: idx
"
stores a reference into a local variable #index
stack: objectref -> nothing
args: index"
context at: idx + 1 put: (self pop).
"Description
The index is an unsigned byte that must be an index into the local
variable array of the current frame (§3.6). The objectref on the
top of the operand stack must be of type returnAddress or of type
reference. It is popped from the operand stack, and the value of
the local variable at index is set to objectref.
Notes
The astore instruction is used with an objectref of type returnAddress
when implementing the finally clauses of the Java programming language
(see Section 7.13, Compiling finally). The aload instruction cannot be
used to load a value of type returnAddress from a local variable onto
he operand stack. This asymmetry with the astore instruction is intentional.
The astore opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index."
"Modified: / 13-03-2011 / 16:57:03 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
athrow
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
baload
self halt
!
bastore
self halt
!
bipush
"
pushes a byte onto the stack as an integer value
stack: nothing -> value
args: byte"
self pushInt: (self fetchByte).
"
The immediate byte is sign-extended to an int value. That value is pushed onto the operand stack.
"
"Modified: / 13-03-2011 / 16:58:07 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
breakpoint
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
caload
self halt
!
castore
self halt
!
checkcast
"
Check whether object is of given type
stack: objref -> objRef
args: indexByte1 indexByte2"
| ref objRef |
ref := constantPool at: self fetchIndex2.
ref isUnresolved
ifTrue:
[ ref := ref javaClass
].
objRef := self pop.
(objRef isNil or: [ (JavaVM canCast: objRef class to: ref) ])
ifTrue: [ self pushRef: objRef. ]
ifFalse: [ JavaVM throwClassCastException ].
"
Description
The objectref must be of type reference. The unsigned indexbyte1 and indexbyte2 are used to
construct an index into the runtime constant pool of the current class (§3.6), where the value
of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item at the index
must be a symbolic reference to a class, array, or interface type. The named class, array,
or interface type is resolved (§5.4.3.1).
If objectref is null or can be cast to the resolved class, array, or interface type, the
operand stack is unchanged; otherwise, the checkcast instruction throws a ClassCastException.
The following rules are used to determine whether an objectref that is not null can be cast
to the resolved type: if S is the class of the object referred to by objectref and T is the
resolved class, array, or interface type, checkcast determines whether objectref can be cast
to type T as follows:
If S is an ordinary (nonarray) class, then:
If T is a class type, then S must be the same class (§2.8.1) as T, or a subclass of T.
If T is an interface type, then S must implement (§2.13) interface T.
If S is an interface type, then:
If T is a class type, then T must be Object (§2.4.7).
If T is an interface type, then T must be the same interface as S or a superinterface
of S (§2.13.2).
If S is a class representing the array type SC[], that is, an array of components of
type SC, then:
If T is a class type, then T must be Object (§2.4.7).
If T is an array type TC[], that is, an array of components of type TC, then one of the
following must be true:
TC and SC are the same primitive type (§2.4.1).
TC and SC are reference types (§2.4.6), and type SC can be cast to TC by recursive
application of these rules.
If T is an interface type, T must be one of the interfaces implemented by arrays (§2.15).
Linking Exceptions
During resolution of the symbolic reference to the class, array, or interface type, any of the
exceptions documented in Section 5.4.3.1 can be thrown.
Runtime Exception
Otherwise, if objectref cannot be cast to the resolved class, array, or interface type,
the checkcast instruction throws a ClassCastException.
Notes
The checkcast instruction is very similar to the instanceof instruction. It differs in
its treatment of null, its behavior when its test fails (checkcast throws an exception,
instanceof pushes a result code), and its effect on the operand stack."
"Modified: / 21-03-2011 / 18:15:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
d2f
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
d2i
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
d2l
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dadd
"
adds two doubles together
stack: value1, value2 -> result
args: nothing"
self pushDouble: (self pop + self pop).
"
Description
Both value1 and value2 must be of type double. The values are popped from the operand
stack and undergo value set conversion (§3.8.3), resulting in value1' and value2'.
The double result is value1' + value2'. The result is pushed onto the operand stack.
The result of a dadd instruction is governed by the rules of IEEE arithmetic:
If either value1' or value2' is NaN, the result is NaN.
The sum of two infinities of opposite sign is NaN.
The sum of two infinities of the same sign is the infinity of that sign.
The sum of an infinity and any finite value is equal to the infinity.
The sum of two zeroes of opposite sign is positive zero.
The sum of two zeroes of the same sign is the zero of that sign.
The sum of a zero and a nonzero finite value is equal to the nonzero value.
The sum of two nonzero finite values of the same magnitude and opposite sign is
positive zero.
In the remaining cases, where neither operand is an infinity, a zero, or NaN and
the values have the same sign or have different magnitudes, the sum is computed
and rounded to the nearest representable value using IEEE 754 round to nearest mode.
If the magnitude is too large to represent as a double, we say the operation overflows;
the result is then an infinity of appropriate sign. If the magnitude is too small to
represent as a double, we say the operation underflows; the result is then a zero of
appropriate sign.
The Java virtual machine requires support of gradual underflow as defined by IEEE 754.
Despite the fact that overflow, underflow, or loss of precision may occur, execution
of a dadd instruction never throws a runtime exception.
"
"Created: / 14-03-2011 / 20:53:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
daload
"
Load double from array
stack: arrayRef index -> value
args: nothing"
self swap.
self pushDouble: (self pop at: (self pop + 1)).
"
Description
The arrayref must be of type reference and must refer to an array whose components are of
type double. The index must be of type int. Both arrayref and index are popped from the
operand stack. The double value in the component of the array at index is retrieved and
pushed onto the operand stack.
Runtime Exceptions
If arrayref is null, daload throws a NullPointerException.
Otherwise, if index is not within the bounds of the array referenced by arrayref, the
daload instruction throws an ArrayIndexOutOfBoundsException.
"
"Modified: / 14-03-2011 / 20:52:09 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dastore
self halt
!
dcmpg
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dcmpl
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dconst: arg
self pushDouble: arg.
"Created: / 14-03-2011 / 18:01:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ddiv
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dload
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dload: idx
"
Load double from local variable
stack: nothing -> value
args: index
"
self pushDouble: (context at: idx + 1).
"
Description
The index is an unsigned byte. Both index and index + 1 must be indices into the local
variable array of the current frame (§3.6). The local variable at index must contain a
double. The value of the local variable at index is pushed onto the operand stack.
Notes
The dload opcode can be used in conjunction with the wide instruction to access a local
variable using a two-byte unsigned index.
"
"Modified: / 13-03-2011 / 16:59:52 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dmul
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dneg
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
drem
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dreturn
"
Return double from method
stack: value -> empty
args: nothing"
self leaveProcessorWith: (self popDouble).
"
Description
The current method must have return type double. The value must be of
type double. If the current method is a synchronized method, the monitor
acquired or reentered on invocation of the method is released or exited
(respectively) as if by execution of a monitorexit instruction. If no
exception is thrown, value is popped from the operand stack of the current
frame (§3.6) and undergoes value set conversion (§3.8.3), resulting in
value'. The value' is pushed onto the operand stack of the frame of the
invoker. Any other values on the operand stack of the current method are
discarded.
The interpreter then returns control to the invoker of the method,
reinstating the frame of the invoker.
Runtime Exceptions
If the current method is a synchronized method and the current thread
is not the owner of the monitor acquired or reentered on invocation of
the method, dreturn throws an IllegalMonitorStateException. This can
happen, for example, if a synchronized method contains a monitorexit
instruction, but no monitorenter instruction, on the object on which
the method is synchronized.
Otherwise, if the virtual machine implementation enforces the rules
on structured use of locks described in §8.13 and if the first of
those rules is violated during invocation of the current method,
then dreturn throws an IllegalMonitorStateException."
"Created: / 14-03-2011 / 13:33:45 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 14-03-2011 / 18:04:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dstore
"
Store double into local variable
stack: value -> nothing
args: index"
context at: self fetchIndex put: (self popDouble).
"
Description
The index is an unsigned byte. Both index and index + 1 must be indices
into the local variable array of the current frame (§3.6). The value on
the top of the operand stack must be of type double. It is popped from
the operand stack and undergoes value set conversion (§3.8.3), resulting
in value'. The local variables at index and index + 1 are set to value'.
Notes
The dstore opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index."
"Created: / 14-03-2011 / 18:04:05 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dstore: idx
"
Store double into local variable
stack: value -> nothing
args: index"
context at: idx + 1 put: (self popDouble).
"
Description
The index is an unsigned byte. Both index and index + 1 must be indices
into the local variable array of the current frame (§3.6). The value on
the top of the operand stack must be of type double. It is popped from
the operand stack and undergoes value set conversion (§3.8.3), resulting
in value'. The local variables at index and index + 1 are set to value'.
Notes
The dstore opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index."
"Modified: / 14-03-2011 / 18:04:18 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dsub
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
dup
"
Duplicate the top operand stack value
stack: value -> value value
args: nothing
"
self pushRef: self tos.
"
Description
Duplicate the top value on the operand stack and push the duplicated value onto the operand stack.
The dup instruction must not be used unless value is a value of a category 1 computational type (§3.11.1).
"
"Modified: / 27-03-2011 / 21:19:49 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dup2
"
Duplicate the top one or two operand stack values
stack v 1: value2 value1 -> value2 value 1 value2 value1 where both value1 and value2 are values of a category 1 computational type (§3.11.1).
stack v 2: value1 -> value1 value1 where value is a value of a category 2 computational type (§3.11.1).
args: nothing
"
| tos |
tos := self popLong.
self pushLong: tos.
self pushLong: tos.
self breakPoint:#mh_instructions.
"
Description
Duplicate the top one or two values on the operand stack and
push the duplicated value or values back onto the operand
stack in the original order.
"
"Modified: / 13-03-2011 / 17:03:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
dup2_x1
self halt
!
dup2_x2
self halt
!
dup_x1
self halt
!
dup_x2
self halt
!
f2d
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
f2i
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
f2l
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fadd
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
faload
self halt
!
fastore
self halt
!
fcmpg
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fcmpl
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fconst: arg
self pushFloat: arg.
"Created: / 14-03-2011 / 17:57:18 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
fdiv
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fload
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fload: idx
"
Load float from local variable
stack: nothing -> value
args: index
"
self pushFloat: (context at: idx + 1).
"
Description
The index is an unsigned byte that must be an index into the local
variable array of the current frame (§3.6). The local variable at
index must contain a float. The value of the local variable at index
is pushed onto the operand stack.
Notes
The fload opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index.
"
"Modified: / 13-03-2011 / 17:05:17 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
fmul
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fneg
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
frem
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
freturn
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
fstore
"
Store float into local variable
stack: value -> nothing
args: index"
self fstore: self fetchIndex.
"
Description
The index is an unsigned byte that must be an index into the local
variable array of the current frame (§3.6). The value on the top of
the operand stack must be of type float. It is popped from the operand
stack and undergoes value set conversion (§3.8.3), resulting in value'.
The value of the local variable at index is set to value'.
Notes
The fstore opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index."
"Created: / 14-03-2011 / 18:01:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
fstore: idx
"
Store float into local variable
stack: value -> nothing
args: index
"
context at: idx + 1 put: (self pop).
"
Description
The index is an unsigned byte that must be an index into the local
variable array of the current frame (§3.6). The value on the top of
the operand stack must be of type float. It is popped from the operand
stack and undergoes value set conversion (§3.8.3), resulting in value'.
The value of the local variable at index is set to value'.
Notes
The fstore opcode can be used in conjunction with the wide instruction
to access a local variable using a two-byte unsigned index.
"
"Modified: / 13-03-2011 / 17:06:07 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
fsub
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
getfield
"gets a field value of an object objectref, where the field is
identified by field reference in the constant pool index (index1 << 8 + index2)
stack: objectRef -> value
args: indexByte1 indexByte2"
| fieldref fieldOwner |
fieldOwner := self pop.
fieldref := constantPool at: self fetchIndex2.
fieldref resolve.
self pushConstant: (fieldref offset).
"
Description
The objectref, which must be of type reference, is popped from the operand stack.
The unsigned indexbyte1 and indexbyte2 are used to construct an index into the
runtime constant pool of the current class (§3.6), where the value of the index
is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item at that index
must be a symbolic reference to a field (§5.1), which gives the name and
descriptor of the field as well as a symbolic reference to the class in which
the field is to be found. The referenced field is resolved (§5.4.3.2). The value
of the referenced field in objectref is fetched and pushed onto the operand stack.
The class of objectref must not be an array. If the field is protected (§4.6),
and it is either a member of the current class or a member of a superclass of
the current class, then the class of objectref must be either the current class
or a subclass of the current class.
Linking Exceptions
During resolution of the symbolic reference to the field, any of the errors
pertaining to field resolution documented in Section 5.4.3.2 can be thrown.
Otherwise, if the resolved field is a static field, getfield throws an
IncompatibleClassChangeError.
Runtime Exception
Otherwise, if objectref is null, the getfield instruction throws a NullPointerException.
Notes
The getfield instruction cannot be used to access the length field of an array.
The arraylength instruction is used instead."
"Created: / 10-03-2011 / 23:34:56 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 16-03-2011 / 15:22:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 04-06-2011 / 18:12:06 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
getstatic
"
Get static field from class
stack: .. -> value
args: indexByte1 indexByte2"
| fieldref |
fieldref := constantPool at: self fetchIndex2.
fieldref resolveStatic.
self pushConstant: (fieldref offset).
"
Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index into the
runtime constant pool of the current class (§3.6), where the value of the index
is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item at that index
must be a symbolic reference to a field (§5.1), which gives the name and descriptor
of the field as well as a symbolic reference to the class or interface in which the
field is to be found. The referenced field is resolved (§5.4.3.2).
On successful resolution of the field, the class or interface that declared the
resolved field is initialized (§5.5) if that class or interface has not already
been initialized.
The value of the class or interface field is fetched and pushed onto the operand stack.
Linking Exceptions
During resolution of the symbolic reference to the class or interface field,
any of the exceptions pertaining to field resolution documented in Section 5.4.3.2
can be thrown.
Otherwise, if the resolved field is not a static (class) field or an interface field,
getstatic throws an IncompatibleClassChangeError.
Runtime Exception
Otherwise, if execution of this getstatic instruction causes initialization of the
referenced class or interface, getstatic may throw an Error as detailed in Section 2.17.5."
"Modified: / 04-06-2011 / 18:15:15 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
goto
"
Branch always
stack: nothing -> nothing
args: branchByte1 branchByte2"
self relativeJump: self fetchBytes2.
"
Description
The unsigned bytes branchbyte1 and branchbyte2 are used to construct a signed 16-bit
branchoffset, where branchoffset is (branchbyte1 << 8) | branchbyte2. Execution proceeds
at that offset from the address of the opcode of this goto instruction. The target
address must be that of an opcode of an instruction within the method that contains
this goto instruction."
"Created: / 14-03-2011 / 20:21:22 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:00 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
goto_w
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
i2d
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
i2f
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
i2l
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
i_dup
self pushInt: (self tos).
"Modified: / 13-03-2011 / 16:40:04 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iadd
"
adds two ints together
stack: value1, value2 -> result
args: nothing"
self pushInt: (self pop + self pop).
"
Description
Both value1 and value2 must be of type int. The values are popped
from the operand stack. The int result is value1 + value2. The result
is pushed onto the operand stack.
The result is the 32 low-order bits of the true mathematical result
in a sufficiently wide two's-complement format, represented as a value
of type int. If overflow occurs, then the sign of the result may not be
the same as the sign of the mathematical sum of the two values.
Despite the fact that overflow may occur, execution of an iadd instruction
never throws a runtime exception."
"Created: / 06-03-2011 / 21:23:42 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 13-03-2011 / 21:51:48 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iaload
"
Load int from array
stack: arrayRef index -> value
args: nothing"
self swap.
self pushInt: (self pop at: (self pop + 1)).
"
Description
The arrayref must be of type reference and must refer to an array whose
components are of type int. The index must be of type int. Both arrayref
and index are popped from the operand stack. The int value in the
component of the array at index is retrieved and pushed onto the operand
stack.
Runtime Exceptions
If arrayref is null, iaload throws a NullPointerException.
Otherwise, if index is not within the bounds of the array referenced by
arrayref, the iaload instruction throws an ArrayIndexOutOfBoundsException."
"Modified: / 14-03-2011 / 20:20:21 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iand
"
Boolean AND int
stack: val1 val2 -> result
args: nothing
"
self pushInt:(self pop bitAnd: self pop).
"
Both value1 and value2 must be of type int. They are popped from the
operand stack. An int result is calculated by taking the bitwise AND
(conjunction) of value1 and value2. The result is pushed onto the
operand stack.
"
"Created: / 14-03-2011 / 17:10:05 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iastore
self halt
!
iconst: arg
self pushInt: arg.
"Created: / 20-03-2011 / 23:35:55 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
idiv
"
Divide int
stack: value1 value2 -> result
args: nothing"
self swap.
self pushInt: (self pop // self pop).
"
Description
Both value1 and value2 must be of type int. The values are popped from the operand stack.
The int result is the value of the Java programming language expression value1 / value2.
The result is pushed onto the operand stack.
An int division rounds towards 0; that is, the quotient produced for int values in n/d is
an int value q whose magnitude is as large as possible while satisfying . Moreover, q is
positive when and n and d have the same sign, but q is negative when and n and d have
opposite signs.
There is one special case that does not satisfy this rule: if the dividend is the negative
integer of largest possible magnitude for the int type, and the divisor is -1, then overflow
occurs, and the result is equal to the dividend. Despite the overflow, no exception is thrown
in this case.
Runtime Exception
If the value of the divisor in an int division is 0, idiv throws an ArithmeticException."
"Created: / 14-03-2011 / 17:50:15 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ifacmpeq
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
ifacmpne
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
ifeq
"
if true, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
stack: value -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self pop = 0 ifTrue: [ self relativeJump: dest ].
"
The value must be of type int. It is popped from the operand stack and
compared against zero. All comparisons are signed. The results of the
comparisons are as follows:
eq succeeds if and only if value = 0
ne succeeds if and only if value 0
lt succeeds if and only if value < 0
le succeeds if and only if value 0
gt succeeds if and only if value > 0
ge succeeds if and only if value 0
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2
are used to construct a signed 16-bit offset, where the offset is
calculated to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds
at that offset from the address of the opcode of this if<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if<cond> instruction."
"Created: / 14-03-2011 / 18:47:27 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:06 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ifge
"
if true, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
stack: value -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self pop >= 0 ifTrue: [ self relativeJump: dest ].
"
The value must be of type int. It is popped from the operand stack and
compared against zero. All comparisons are signed. The results of the
comparisons are as follows:
eq succeeds if and only if value = 0
ne succeeds if and only if value 0
lt succeeds if and only if value < 0
le succeeds if and only if value 0
gt succeeds if and only if value > 0
ge succeeds if and only if value 0
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2
are used to construct a signed 16-bit offset, where the offset is
calculated to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds
at that offset from the address of the opcode of this if<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if<cond> instruction."
"Created: / 14-03-2011 / 18:48:02 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:11 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ifgt
"
if true, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
stack: value -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self pop > 0 ifTrue: [ self relativeJump: dest ].
"
The value must be of type int. It is popped from the operand stack and
compared against zero. All comparisons are signed. The results of the
comparisons are as follows:
eq succeeds if and only if value = 0
ne succeeds if and only if value 0
lt succeeds if and only if value < 0
le succeeds if and only if value 0
gt succeeds if and only if value > 0
ge succeeds if and only if value 0
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2
are used to construct a signed 16-bit offset, where the offset is
calculated to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds
at that offset from the address of the opcode of this if<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if<cond> instruction."
"Created: / 14-03-2011 / 18:48:16 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:14 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ificmpeq
"
Branch if int comparison succeeds
stack: value1 value2 -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
(self pop = self pop) ifTrue: [ self relativeJump: dest ].
"
Description
Both value1 and value2 must be of type int. They are both popped from
the operand stack and compared. All comparisons are signed. The results
of the comparison are as follows:
eq succeeds if and only if value1 = value2
ne succeeds if and only if value1 ~= value2
lt succeeds if and only if value1 < value2
le succeeds if and only if value1 value2
gt succeeds if and only if value1 > value2
ge succeeds if and only if value1 value2
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are
used to construct a signed 16-bit offset, where the offset is calculated
to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds at that
offset from the address of the opcode of this if_icmp<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if_icmp<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if_icmp<cond> instruction."
"Created: / 14-03-2011 / 18:49:36 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:18 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ificmpge
"
Branch if int comparison succeeds
stack: value1 value2 -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self swap.
(self pop >= self pop) ifTrue: [ self relativeJump: dest ]
"
Description
Both value1 and value2 must be of type int. They are both popped from
the operand stack and compared. All comparisons are signed. The results
of the comparison are as follows:
eq succeeds if and only if value1 = value2
ne succeeds if and only if value1 ~= value2
lt succeeds if and only if value1 < value2
le succeeds if and only if value1 <= value2
gt succeeds if and only if value1 > value2
ge succeeds if and only if value1 >= value2
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are
used to construct a signed 16-bit offset, where the offset is calculated
to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds at that
offset from the address of the opcode of this if_icmp<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if_icmp<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if_icmp<cond> instruction."
"Created: / 14-03-2011 / 18:52:19 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:22 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ificmpgt
"
Branch if int comparison succeeds
stack: value1 value2 -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self swap.
(self pop > self pop) ifTrue: [ self relativeJump: dest ]
"
Description
Both value1 and value2 must be of type int. They are both popped from
the operand stack and compared. All comparisons are signed. The results
of the comparison are as follows:
eq succeeds if and only if value1 = value2
ne succeeds if and only if value1 ~= value2
lt succeeds if and only if value1 < value2
le succeeds if and only if value1 <= value2
gt succeeds if and only if value1 > value2
ge succeeds if and only if value1 >= value2
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are
used to construct a signed 16-bit offset, where the offset is calculated
to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds at that
offset from the address of the opcode of this if_icmp<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if_icmp<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if_icmp<cond> instruction."
"Created: / 14-03-2011 / 21:00:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:25 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ificmple
"
Branch if int comparison succeeds
stack: value1 value2 -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self swap.
(self pop <= self pop) ifTrue: [ self relativeJump: dest ]
"
Description
Both value1 and value2 must be of type int. They are both popped from
the operand stack and compared. All comparisons are signed. The results
of the comparison are as follows:
eq succeeds if and only if value1 = value2
ne succeeds if and only if value1 ~= value2
lt succeeds if and only if value1 < value2
le succeeds if and only if value1 <= value2
gt succeeds if and only if value1 > value2
ge succeeds if and only if value1 >= value2
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are
used to construct a signed 16-bit offset, where the offset is calculated
to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds at that
offset from the address of the opcode of this if_icmp<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if_icmp<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if_icmp<cond> instruction."
"Created: / 14-03-2011 / 21:00:44 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ificmplt
"
Branch if int comparison succeeds
stack: value1 value2 -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self swap.
(self pop < self pop) ifTrue: [ self relativeJump: dest ]
"
Description
Both value1 and value2 must be of type int. They are both popped from
the operand stack and compared. All comparisons are signed. The results
of the comparison are as follows:
eq succeeds if and only if value1 = value2
ne succeeds if and only if value1 ~= value2
lt succeeds if and only if value1 < value2
le succeeds if and only if value1 <= value2
gt succeeds if and only if value1 > value2
ge succeeds if and only if value1 >= value2
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are
used to construct a signed 16-bit offset, where the offset is calculated
to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds at that
offset from the address of the opcode of this if_icmp<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if_icmp<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if_icmp<cond> instruction."
"Created: / 14-03-2011 / 21:00:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:32 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ificmpne
"
Branch if int comparison succeeds
stack: value1 value2 -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
(self pop ~= self pop) ifTrue: [ self relativeJump: dest ].
"
Description
Both value1 and value2 must be of type int. They are both popped from
the operand stack and compared. All comparisons are signed. The results
of the comparison are as follows:
eq succeeds if and only if value1 = value2
ne succeeds if and only if value1 ~= value2
lt succeeds if and only if value1 < value2
le succeeds if and only if value1 value2
gt succeeds if and only if value1 > value2
ge succeeds if and only if value1 value2
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are
used to construct a signed 16-bit offset, where the offset is calculated
to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds at that
offset from the address of the opcode of this if_icmp<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if_icmp<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if_icmp<cond> instruction."
"Created: / 14-03-2011 / 20:59:43 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:35 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ifle
"
if true, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
stack: value -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self pop <= 0 ifTrue: [ self relativeJump: dest ].
"
The value must be of type int. It is popped from the operand stack and
compared against zero. All comparisons are signed. The results of the
comparisons are as follows:
eq succeeds if and only if value = 0
ne succeeds if and only if value 0
lt succeeds if and only if value < 0
le succeeds if and only if value 0
gt succeeds if and only if value > 0
ge succeeds if and only if value 0
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2
are used to construct a signed 16-bit offset, where the offset is
calculated to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds
at that offset from the address of the opcode of this if<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if<cond> instruction."
"Created: / 14-03-2011 / 18:48:10 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:39 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iflt
"
if true, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
stack: value -> nothing
args: branchByte1 branchByte2"
| dest |
dest := self fetchBytes2.
self pop < 0 ifTrue: [ self relativeJump: dest ].
"
The value must be of type int. It is popped from the operand stack and
compared against zero. All comparisons are signed. The results of the
comparisons are as follows:
eq succeeds if and only if value = 0
ne succeeds if and only if value 0
lt succeeds if and only if value < 0
le succeeds if and only if value 0
gt succeeds if and only if value > 0
ge succeeds if and only if value 0
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2
are used to construct a signed 16-bit offset, where the offset is
calculated to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds
at that offset from the address of the opcode of this if<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if<cond> instruction."
"Created: / 14-03-2011 / 18:47:49 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:43 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ifne
"
if value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
stack: value -> nothing
args: branchByte1 branchByte2"
"/ -1 in block - because we already increased pc to point to the next instruction
| dest |
dest := self fetchBytes2.
self pop ~= 0 ifTrue: [ self relativeJump: dest ].
"
The value must be of type int. It is popped from the operand stack and
compared against zero. All comparisons are signed. The results of the
comparisons are as follows:
eq succeeds if and only if value = 0
ne succeeds if and only if value ~= 0
lt succeeds if and only if value < 0
le succeeds if and only if value <= 0
gt succeeds if and only if value > 0
ge succeeds if and only if value >= 0
If the comparison succeeds, the unsigned branchbyte1 and branchbyte2
are used to construct a signed 16-bit offset, where the offset is
calculated to be (branchbyte1 << 8) | branchbyte2. Execution then proceeds
at that offset from the address of the opcode of this if<cond> instruction.
The target address must be that of an opcode of an instruction within the
method that contains this if<cond> instruction.
Otherwise, execution proceeds at the address of the instruction following
this if<cond> instruction."
"Created: / 06-03-2011 / 22:57:49 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 21-03-2011 / 18:20:46 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ifnonnull
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
ifnull
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
iinc
"
Increment local variable by constant
stack: nothing -> nothing
args: index const
"
| index const |
index := self fetchIndex.
const := self fetchByte.
context at: index + 1 put: ((context at: index + 1) + const).
"
Description
The index is an unsigned byte that must be an index into the local variable
array of the current frame (§3.6). The const is an immediate signed byte.
The local variable at index must contain an int. The value const is first
sign-extended to an int, and then the local variable at index is incremented
by that amount.
Notes
The iinc opcode can be used in conjunction with the wide instruction to access
a local variable using a two-byte unsigned index and to increment it by a two-byte
immediate value.
"
"Created: / 14-03-2011 / 17:22:22 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iload
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
iload: idx
"
loads an int value from a local variable #index
stack: nothing -> value
args: index"
self pushInt: (context at: idx + 1).
"
The index is an unsigned byte that must be an index into the local variable array
of the current frame (§3.6). The local variable at index must contain an int.
The value of the local variable at index is pushed onto the operand stack.
Notes
The iload opcode can be used in conjunction with the wide instruction to
access a local variable using a two-byte unsigned index."
"Modified: / 17-03-2011 / 17:33:36 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
imul
"multiply two integers
stack: value1, value2 -> result
args: nothing"
self pushInt: (self pop * self pop).
"
Both value1 and value2 must be of type int. The values are popped
from the operand stack. The int result is value1 * value2. The result
is pushed onto the operand stack.
The result is the 32 low-order bits of the true mathematical result
in a sufficiently wide two's-complement format, represented as a value
of type int. If overflow occurs, then the sign of the result may not
be the same as the sign of the mathematical sum of the two values.
Despite the fact that overflow may occur, execution of an imul
instruction never throws a runtime exception."
"Created: / 06-03-2011 / 22:42:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 13-03-2011 / 17:24:56 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ineg
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
instanceof
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
int2byte
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
int2char
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
int2short
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
invinterface
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
invnonvirt
"
Invoke instance method; special handling for superclass, private, and instance initialization method invocations
stack: objRef [args] -> ..
args: indexByte1 indexByte2"
| methodToBeInvoked methodReceiver methodNumArgs methodArgs result |
methodToBeInvoked := constantPool at: self fetchIndex2.
methodReceiver := self pop.
methodNumArgs := methodToBeInvoked javaNumArgs.
methodArgs := Array new: methodNumArgs.
methodNumArgs to: 1
by: -1
do: [:index | methodArgs at: index put: self pop ].
result := self
interpretInner: methodToBeInvoked
receiver: methodReceiver
arguments: methodArgs.
self pushRef: result.
"
Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool
of the current class (§3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The
runtime constant pool item at that index must be a symbolic reference to a method (§5.1), which gives
the name and descriptor (§4.3.3) of the method as well as a symbolic reference to the class in which
the method is to be found. The named method is resolved (§5.4.3.3). Finally, if the resolved method
is protected (§4.6), and it is either a member of the current class or a member of a superclass of
the current class, then the class of objectref must be either the current class or a subclass of the
current class.
Next, the resolved method is selected for invocation unless all of the following conditions are true:
The ACC_SUPER flag (see Table 4.1, Class access and property modifiers) is set for the current class.
The class of the resolved method is a superclass of the current class.
The resolved method is not an instance initialization method (§3.9).
If the above conditions are true, the actual method to be invoked is selected by the following lookup
procedure. Let C be the direct superclass of the current class:
If C contains a declaration for an instance method with the same name and descriptor as the resolved
method, then this method will be invoked. The lookup procedure terminates.
Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct
superclass of C. The method to be invoked is the result of the recursive invocation of this lookup
procedure.
Otherwise, an AbstractMethodError is raised.
The objectref must be of type reference and must be followed on the operand stack by nargs argument
values, where the number, type, and order of the values must be consistent with the descriptor of the
selected instance method.
If the method is synchronized, the monitor associated with objectref is acquired or reentered.
If the method is not native, the nargs argument values and objectref are popped from the operand stack.
A new frame is created on the Java virtual machine stack for the method being invoked. The objectref
and the argument values are consecutively made the values of local variables of the new frame, with
objectref in local variable 0, arg1 in local variable 1 (or, if arg1 is of type long or double, in
local variables 1 and 2), and so on. Any argument value that is of a floating-point type undergoes
value set conversion (§3.8.3) prior to being stored in a local variable. The new frame is then made
current, and the Java virtual machine pc is set to the opcode of the first instruction of the method
to be invoked. Execution continues with the first instruction of the method.
If the method is native and the platform-dependent code that implements it has not yet been bound (§5.6)
into the Java virtual machine, that is done. The nargs argument values and objectref are popped from
the operand stack and are passed as parameters to the code that implements the method. Any argument
value that is of a floating-point type undergoes value set conversion (§3.8.3) prior to being passed
as a parameter. The parameters are passed and the code is invoked in an implementation-dependent
manner. When the platform-dependent code returns, the following take place:
If the native method is synchronized, the monitor associated with objectref is released or exited as
if by execution of a monitorexit instruction.
If the native method returns a value, the return value of the platform-dependent code is converted in
an implementation-dependent way to the return type of the native method and pushed onto the operand stack.
Linking Exceptions
During resolution of the symbolic reference to the method, any of the exceptions pertaining to method
resolution documented in Section 5.4.3.3 can be thrown.
Otherwise, if the resolved method is an instance initialization method, and the class in which it is
declared is not the class symbolically referenced by the instruction, a NoSuchMethodError is thrown.
Otherwise, if the resolved method is a class (static) method, the invokespecial instruction throws an
IncompatibleClassChangeError.
Otherwise, if no method matching the resolved name and descriptor is selected, invokespecial throws
an AbstractMethodError.
Otherwise, if the selected method is abstract, invokespecial throws an AbstractMethodError.
Runtime Exceptions
Otherwise, if objectref is null, the invokespecial instruction throws a NullPointerException.
Otherwise, if the selected method is native and the code that implements the method cannot be bound,
invokespecial throws an UnsatisfiedLinkError.
Notes
The difference between the invokespecial and the invokevirtual instructions is that invokevirtual
invokes a method based on the class of the object. The invokespecial instruction is used to invoke
instance initialization methods (§3.9) as well as private methods and methods of a superclass of
the current class.
The invokespecial instruction was named invokenonvirtual prior to Sun's JDK release 1.0.2.
The nargs argument values and objectref are not one-to-one with the first nargs + 1 local variables.
Argument values of types long and double must be stored in two consecutive local variables, thus more
than nargs local variables may be required to pass nargs argument values to the invoked method."
"Modified: / 31-03-2011 / 16:34:52 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
invstatic
"
Invoke a class (static) method
stack: [arg1 [args2 ...]] -> nothing
args: indexByte1 indexByte2"
| methodToBeInvoked methodNumArgs args argSignatures result |
methodToBeInvoked := (constantPool at: self fetchIndex2) resolve.
methodToBeInvoked ifNil: [self halt].
methodNumArgs := methodToBeInvoked javaNumArgs.
argSignatures := methodToBeInvoked argSignature.
args := Array new: methodNumArgs.
methodNumArgs to: 1 by: -1 do: [
:index |
args at: index put: self pop
].
result := self
interpretInner: methodToBeInvoked
receiver: receiver
arguments: args.
methodToBeInvoked returnsVoid ifFalse: [
self pushConstant: result
].
"
Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index into the
runtime constant pool of the current class (§3.6), where the value of the index is
(indexbyte1 << 8) | indexbyte2. The runtime constant pool item at that index must
be a symbolic reference to a method (§5.1), which gives the name and descriptor (§4.3.3)
of the method as well as a symbolic reference to the class in which the method is to
be found. The named method is resolved (§5.4.3.3). The method must not be the class
or interface initialization method (§3.9). It must be static, and therefore cannot be
abstract.
On successful resolution of the method, the class that declared the resolved field is
initialized (§5.5) if that class has not already been initialized.
The operand stack must contain nargs argument values, where the number, type, and order
of the values must be consistent with the descriptor of the resolved method.
If the method is synchronized, the monitor associated with the resolved class is acquired
or reentered.
If the method is not native, the nargs argument values are popped from the operand stack.
A new frame is created on the Java virtual machine stack for the method being invoked.
The nargs argument values are consecutively made the values of local variables of the
new frame, with arg1 in local variable 0 (or, if arg1 is of type long or double, in local
variables 0 and 1) and so on. Any argument value that is of a floating-point type undergoes
value set conversion (§3.8.3) prior to being stored in a local variable. The new frame is
then made current, and the Java virtual machine pc is set to the opcode of the first
nstruction of the method to be invoked. Execution continues with the first instruction
of the method.
If the method is native and the platform-dependent code that implements it has not yet
been bound (§5.6) into the Java virtual machine, that is done. The nargs argument values
are popped from the operand stack and are passed as parameters to the code that
implements the method. Any argument value that is of a floating-point type undergoes
value set conversion (§3.8.3) prior to being passed as a parameter. The parameters are
passed and the code is invoked in an implementation-dependent manner. When the
platform-dependent code returns, the following take place:
If the native method is synchronized, the monitor associated with the resolved class
is released or exited as if by execution of a monitorexit instruction.
If the native method returns a value, the return value of the platform-dependent code
is converted in an implementation-dependent way to the return type of the native
method and pushed onto the operand stack.
Linking Exceptions
During resolution of the symbolic reference to the method, any of the exceptions
pertaining to method resolution documented in Section 5.4.3.3 can be thrown.
Otherwise, if the resolved method is an instance method, the invokestatic instruction
throws an IncompatibleClassChangeError.
Runtime Exceptions
Otherwise, if execution of this invokestatic instruction causes initialization of the
referenced class, invokestatic may throw an Error as detailed in Section 2.17.5.
Otherwise, if the resolved method is native and the code that implements the method
cannot be bound, invokestatic throws an UnsatisfiedLinkError.
Notes
The nargs argument values are not one-to-one with the first nargs local variables.
Argument values of types long and double must be stored in two consecutive local variables,
thus more than nargs local variables may be required to pass nargs argument values to
the invoked method."
"Created: / 24-02-2011 / 10:37:05 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 25-02-2011 / 00:18:30 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 24-02-2011 / 22:13:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 04-06-2011 / 18:13:02 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
invvirt
"
Invoke instance method; dispatch based on class
stack: objRef args -> ..
args: indexByte1 indexByte2"
| methodOwner methodRef resolvedMethod methodNumArgs args result |
methodRef := constantPool at: self fetchIndex2.
methodOwner := self pop.
resolvedMethod := methodRef resolve.
methodNumArgs := resolvedMethod javaNumArgs.
args := Array new: methodNumArgs.
methodNumArgs to: 1 by: -1 do: [
:index |
args at: index put: self pop
].
result := self
interpretInner: (methodOwner class lookupMethodFor: resolvedMethod selector)
receiver: methodOwner
arguments: args.
resolvedMethod returnsVoid ifFalse: [
self pushConstant: result
].
"
Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index into the
runtime constant pool of the current class (§3.6), where the value of the index
is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item at that index
must be a symbolic reference to a method (§5.1), which gives the name and descriptor
(§4.3.3) of the method as well as a symbolic reference to the class in which the
method is to be found. The named method is resolved (§5.4.3.3). The method must
not be an instance initialization method (§3.9) or the class or interface
initialization method (§3.9). Finally, if the resolved method is protected (§4.6),
and it is either a member of the current class or a member of a superclass of the
current class, then the class of objectref must be either the current class or a
subclass of the current class.
Let C be the class of objectref. The actual method to be invoked is selected by
the following lookup procedure:
If C contains a declaration for an instance method with the same name and descriptor
as the resolved method, and the resolved method is accessible from C, then this is
the method to be invoked, and the lookup procedure terminates.
Otherwise, if C has a superclass, this same lookup procedure is performed recursively
using the direct superclass of C ; the method to be invoked is the result of the
recursive invocation of this lookup procedure.
Otherwise, an AbstractMethodError is raised.
The objectref must be followed on the operand stack by nargs argument values,
where the number, type, and order of the values must be consistent with the descriptor
of the selected instance method.
If the method is synchronized, the monitor associated with objectref is acquired or
reentered.
If the method is not native, the nargs argument values and objectref are popped from
the operand stack. A new frame is created on the Java virtual machine stack for the
method being invoked. The objectref and the argument values are consecutively made
the values of local variables of the new frame, with objectref in local variable 0,
arg1 in local variable 1 (or, if arg1 is of type long or double, in local variables 1
and 2), and so on. Any argument value that is of a floating-point type undergoes
value set conversion (§3.8.3) prior to being stored in a local variable. The new
frame is then made current, and the Java virtual machine pc is set to the opcode
of the first instruction of the method to be invoked. Execution continues with the
first instruction of the method.
If the method is native and the platform-dependent code that implements it has not
yet been bound (§5.6) into the Java virtual machine, that is done. The nargs argument
values and objectref are popped from the operand stack and are passed as parameters
to the code that implements the method. Any argument value that is of a floating-point
type undergoes value set conversion (§3.8.3) prior to being passed as a parameter. The
parameters are passed and the code is invoked in an implementation-dependent manner.
When the platform-dependent code returns, the following take place:
If the native method is synchronized, the monitor associated with objectref is released
or exited as if by execution of a monitorexit instruction.
If the native method returns a value, the return value of the platform-dependent code
is converted in an implementation-dependent way to the return type of the native method
and pushed onto the operand stack.
Linking Exceptions
During resolution of the symbolic reference to the method, any of the exceptions
pertaining to method resolution documented in Section 5.4.3.3 can be thrown.
Otherwise, if the resolved method is a class (static) method, the invokevirtual instruction
throws an IncompatibleClassChangeError.
Runtime Exceptions
Otherwise, if objectref is null, the invokevirtual instruction throws a NullPointerException.
Otherwise, if no method matching the resolved name and descriptor is selected, invokevirtual
throws an AbstractMethodError.
Otherwise, if the selected method is abstract, invokevirtual throws an AbstractMethodError.
Otherwise, if the selected method is native and the code that implements the method cannot
be bound, invokevirtual throws an UnsatisfiedLinkError.
Notes
The nargs argument values and objectref are not one-to-one with the first nargs + 1 local
variables. Argument values of types long and double must be stored in two consecutive local
variables, thus more than nargs local variables may be required to pass nargs argument
values to the invoked method."
"Modified: / 04-06-2011 / 18:13:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ior
"
Boolean OR int
stack: val1 val2 -> result
args: nothing"
self pushInt: (self pop bitOr: self pop).
"
Description
Both value1 and value2 must be of type int. They are popped from the operand stack.
An int result is calculated by taking the bitwise inclusive OR of value1 and value2.
The result is pushed onto the operand stack.
"
"Created: / 14-03-2011 / 18:20:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
irem
"
Remainder int
stack: value1 value2 -> result
args: nothing"
| value1 value2 |
value2 := self pop.
value1 := self pop.
self pushInt: (value1 - ((value1 // value2) * value2)).
"
Description
Both value1 and value2 must be of type int. The values are popped from the operand stack.
The int result is value1 - (value1 / value2) * value2. The result is pushed onto the
operand stack.
The result of the irem instruction is such that (a/b)*b + (a%b) is equal to a. This identity
holds even in the special case in which the dividend is the negative int of largest possible
magnitude for its type and the divisor is -1 (the remainder is 0). It follows from this rule
that the result of the remainder operation can be negative only if the dividend is negative
and can be positive only if the dividend is positive. Moreover, the magnitude of the result
is always less than the magnitude of the divisor.
Runtime Exception
If the value of the divisor for an int remainder operator is 0, irem throws an ArithmeticException."
"Modified: / 14-03-2011 / 17:32:10 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ireturn
"
Return int from method
stack: value -> nothing
args: nothing"
self leaveProcessorWith: (self pop).
"
Description
The current method must have return type boolean, byte, short,
char, or int. The value must be of type int. If the current method
is a synchronized method, the monitor acquired or reentered on
invocation of the method is released or exited (respectively) as
if by execution of a monitorexit instruction. If no exception is
thrown, value is popped from the operand stack of the current frame
(§3.6) and pushed onto the operand stack of the frame of the invoker.
Any other values on the operand stack of the current method are discarded.
The interpreter then returns control to the invoker of the method,
reinstating the frame of the invoker.
Runtime Exceptions
If the current method is a synchronized method and the current thread
is not the owner of the monitor acquired or reentered on invocation of
the method, ireturn throws an IllegalMonitorStateException. This can
happen, for example, if a synchronized method contains a monitorexit
instruction, but no monitorenter instruction, on the object on which
the method is synchronized.
Otherwise, if the virtual machine implementation enforces the rules
on structured use of locks described in Section 8.13 and if the first
of those rules is violated during invocation of the current method,
then ireturn throws an IllegalMonitorStateException."
"Created: / 06-03-2011 / 21:24:33 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 13-03-2011 / 17:42:29 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ishl
"
Shift left int
stack: val1 val2 -> result
args: nothing"
self swap.
self pushInt: (self pop bitShift32: self pop).
"
Description
Both value1 and value2 must be of type int. The values are popped from the operand
stack. An int result is calculated by shifting value1 left by s bit positions, where
s is the value of the low 5 bits of value2. The result is pushed onto the operand stack.
Notes
This is equivalent (even if overflow occurs) to multiplication by 2 to the power s.
The shift distance actually used is always in the range 0 to 31, inclusive, as if
value2 were subjected to a bitwise logical AND with the mask value 0x1f."
"Created: / 14-03-2011 / 17:12:01 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 14-03-2011 / 19:01:15 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ishr
"
Shift right int
stack: val1 val2 -> result
args: nothing"
self swap.
self pushInt: (self pop rightShift: (self pop bitAnd: 2r11111)).
"
Description
Both value1 and value2 must be of type int. The values are popped from the operand
stack. An int result is calculated by shifting value1 right by s bit positions,
with sign extension, where s is the value of the low 5 bits of value2. The result
is pushed onto the operand stack.
Notes
The resulting value is , where s is value2 & 0x1f. For nonnegative value1, this
is equivalent to truncating int division by 2 to the power s. The shift distance
actually used is always in the range 0 to 31, inclusive, as if value2 were
subjected to a bitwise logical AND with the mask value 0x1f."
"Created: / 14-03-2011 / 17:19:08 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
istore
"superclass JavaByteCodeProcessor says that I am responsible to implement this method"
^ self shouldImplement
!
istore: idx
"store int value into variable #index
stack: value -> nothing
args: index"
context at: (idx + 1) put: (self pop).
"
Description
The index is an unsigned byte that must be an index into the local variable
array of the current frame (§3.6). The value on the top of the operand stack
must be of type int. It is popped from the operand stack, and the value of
the local variable at index is set to value.
Notes
The istore opcode can be used in conjunction with the wide instruction to
access a local variable using a two-byte unsigned index."
"Modified: / 14-03-2011 / 20:03:50 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
isub
"
int substract
stack: value1, value2 -> result
args: nothing"
self pushInt: (0 - self pop + self pop).
"
Both value1 and value2 must be of type int. The values are
popped from the operand stack. The int result is value1 - value2.
The result is pushed onto the operand stack.
For int subtraction, a - b produces the same result as a + (-b).
For int values, subtraction from zero is the same as negation.
The result is the 32 low-order bits of the true mathematical result
in a sufficiently wide two's-complement format, represented
as a value of type int. If overflow occurs, then the sign of
the result may not be the same as the sign of the mathematical
sum of the two values.
Despite the fact that overflow may occur, execution of an isub
instruction never throws a runtime exception."
"Created: / 06-03-2011 / 23:14:03 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 13-03-2011 / 17:13:59 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
iushr
"
Logical shift right int
stack: value1 value2 -> result
args: nothing"
self swap.
self pushInt: (self pop unsignedBitShift32: self pop).
"
Description
Both value1 and value2 must be of type int. The values are popped from the
operand stack. An int result is calculated by shifting value1 right by s
bit positions, with zero extension, where s is the value of the low 5 bits
of value2. The result is pushed onto the operand stack.
Notes
If value1 is positive and s is value2 & 0x1f, the result is the same as
that of value1 >> s; if value1 is negative, the result is equal to the
value of the expression (value1 >> s) + (2 << ~s). The addition of the
(2 << ~s) term cancels out the propagated sign bit. The shift distance
actually used is always in the range 0 to 31, inclusive."
"Created: / 14-03-2011 / 18:58:24 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ixor
"
Boolean XOR int
stack: value1 value -> result
args: nothing"
self pushInt: (self pop bitXor: self pop).
"
Description
Both value1 and value2 must be of type int. They are popped from the operand
stack. An int result is calculated by taking the bitwise exclusive OR of
value1 and value2. The result is pushed onto the operand stack."
"Created: / 14-03-2011 / 18:07:07 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 17-03-2011 / 17:35:39 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
jsr
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
jsr_w
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
l2d
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
l2f
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
l2i
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
ladd
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
laload
self halt
!
land
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lastore
self halt
!
lcmp
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lconst: arg
"
Push long constant
stack: nothing -> const
arg: nothing"
self pushLong: arg.
"
Push the long constant <l> (0 or 1) onto the operand stack."
"Created: / 17-03-2011 / 15:31:38 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 17-03-2011 / 17:03:12 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ldc1
"
Push item from runtime constant pool
stack: nothing -> value
args: index"
self pushRef: (constantPool at: self fetchIndex).
"
Description
The index is an unsigned byte that must be a valid index into the runtime constant
pool of the current class (§3.6). The runtime constant pool entry at index either
must be a runtime constant of type int or float, or must be a symbolic reference
to a string literal (§5.1).
If the runtime constant pool entry is a runtime constant of type int or float, the
numeric value of that runtime constant is pushed onto the operand stack as an int
or float, respectively.
Otherwise, the runtime constant pool entry must be a reference to an instance of
class String representing a string literal (§5.1). A reference to that instance,
value, is pushed onto the operand stack.
Notes
The ldc instruction can only be used to push a value of type float taken from the float value set (§3.3.2) because a constant of type float in the constant pool (§4.4.4) must be taken from the float value set."
"Modified: / 14-03-2011 / 16:04:56 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ldc2
"
push item from runtime constant pool (wide index)
stack: .. -> value
args: indexByte1 indexByte2"
self pushRef: (constantPool at: self fetchIndex2).
"
Description
The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned 16-bit
index into the runtime constant pool of the current class (§3.6), where the
value of the index is calculated as (indexbyte1 << 8) | indexbyte2. The index
must be a valid index into the runtime constant pool of the current class.
The runtime constant pool entry at the index either must be a runtime constant
of type int or float, or must be a symbolic reference to a string literal (§5.1).
If the runtime constant pool entry is a runtime constant of type int or float,
the numeric value of that runtime constant is pushed onto the operand stack as
an int or float, respectively.
Otherwise, the runtime constant pool entry must be a reference to an instance
of class String representing a string literal (§5.1). A reference to that
instance, value, is pushed onto the operand stack.
Notes
The ldc_w instruction is identical to the ldc instruction except for its wider
runtime constant pool index.
The ldc_w instruction can only be used to push a value of type float taken from
the float value set (§3.3.2) because a constant of type float in the constant
pool (§4.4.4) must be taken from the float value set."
"Modified: / 28-03-2011 / 18:04:31 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ldc2w
"
Push long or double from runtime constant pool (wide index)
stack: .. -> value
args: indexByte1 indexByte2
"
self ldc2.
"
Description
The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned 16-bit index
into the runtime constant pool of the current class (§3.6), where the value of the
index is calculated as (indexbyte1 << 8) | indexbyte2. The index must be a valid
index into the runtime constant pool of the current class. The runtime constant pool
entry at the index must be a runtime constant of type long or double (§5.1). The
numeric value of that runtime constant is pushed onto the operand stack as a long
or double, respectively.
Notes
Only a wide-index version of the ldc2_w instruction exists; there is no ldc2 instruction
that pushes a long or double with a single-byte index.
The ldc2_w instruction can only be used to push a value of type double taken from the
double value set (§3.3.2) because a constant of type double in the constant pool (§4.4.5)
must be taken from the double value set.
"
"Modified: / 27-03-2011 / 21:12:38 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ldiv
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lload
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lload: idx
"
Load long from local variable
stack: nothing -> value
args: index"
self pushLong: (context at: idx + 1).
"
Description
The index is an unsigned byte. Both index and index + 1 must be indices
into the local variable array of the current frame (§3.6). The local variable
at index must contain a long. The value of the local variable at index is
pushed onto the operand stack.
Notes
The lload opcode can be used in conjunction with the wide instruction to
access a local variable using a two-byte unsigned index."
"Modified: / 13-03-2011 / 17:24:36 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
lmul
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lneg
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lookupswtch
"
Access jump table by key match and jump
stack: key -> ..
args: insane"
| key jmpDest default npairs result |
key := self pop asInteger.
self skipPadding.
default := self fetchBytes4.
npairs := self fetchBytes4.
npairs
timesRepeat:
[
key = self fetchBytes4
ifTrue: [ jmpDest := self fetchBytes4 ]
ifFalse: [ self fetchBytes4 ] ].
jmpDest ifNil: [ jmpDest := default. ].
self relativeJump: jmpDest.
"
Description
A lookupswitch is a variable-length instruction. Immediately after the lookupswitch
opcode, between zero and three null bytes (zeroed bytes, not the null object) are
inserted as padding. The number of null bytes is chosen so that the defaultbyte1 begins
at an address that is a multiple of four bytes from the start of the current method
(the opcode of its first instruction). Immediately after the padding follow a series
of signed 32-bit values: default, npairs, and then npairs pairs of signed 32-bit values.
The npairs must be greater than or equal to 0. Each of the npairs pairs consists of an
int match and a signed 32-bit offset. Each of these signed 32-bit values is constructed
from four unsigned bytes as (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4.
The table match-offset pairs of the lookupswitch instruction must be sorted in increasing
numerical order by match.
The key must be of type int and is popped from the operand stack. The key is compared
against the match values. If it is equal to one of them, then a target address is
calculated by adding the corresponding offset to the address of the opcode of this
lookupswitch instruction. If the key does not match any of the match values, the target
address is calculated by adding default to the address of the opcode of this lookupswitch
instruction. Execution then continues at the target address.
The target address that can be calculated from the offset of each match-offset pair, as
well as the one calculated from default, must be the address of an opcode of an instruction
within the method that contains this lookupswitch instruction.
Notes
The alignment required of the 4-byte operands of the lookupswitch instruction guarantees
4-byte alignment of those operands if and only if the method that contains the lookupswitch
is positioned on a 4-byte boundary.
The match-offset pairs are sorted to support lookup routines that are quicker than linear
search."
"Modified: / 21-03-2011 / 18:38:16 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
lor
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lrem
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lreturn
"
Return long from method
stack: value -> empty
args: nothing"
self leaveProcessorWith: (self pop).
"
Description
The current method must have return type long. The value must be of type
long. If the current method is a synchronized method, the monitor acquired
or reentered on invocation of the method is released or exited (respectively)
as if by execution of a monitorexit instruction. If no exception is thrown,
value is popped from the operand stack of the current frame (§3.6) and pushed
onto the operand stack of the frame of the invoker. Any other values on the
operand stack of the current method are discarded.
The interpreter then returns control to the invoker of the method, reinstating
the frame of the invoker.
Runtime Exceptions
If the current method is a synchronized method and the current thread is not
the owner of the monitor acquired or reentered on invocation of the method,
lreturn throws an IllegalMonitorStateException. This can happen, for example,
if a synchronized method contains a monitorexit instruction, but no monitorenter
instruction, on the object on which the method is synchronized.
Otherwise, if the virtual machine implementation enforces the rules on structured
use of locks described in Section 8.13 and if the first of those rules is
violated during invocation of the current method, then lreturn throws an
IllegalMonitorStateException."
"Created: / 14-03-2011 / 13:40:58 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
lshl
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lshr
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lstore
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lstore: idx
"
Store long into local variable
stack: value -> nothing
args: index"
self istore: idx.
"
Description
The index is an unsigned byte. Both index and index + 1 must be indices
into the local variable array of the current frame (§3.6). The value on
the top of the operand stack must be of type long. It is popped from the
operand stack, and the local variables at index and index + 1 are set to
value.
Notes
The lstore opcode can be used in conjunction with the wide instruction to
access a local variable using a two-byte unsigned index."
"Modified: / 14-03-2011 / 17:55:46 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
lsub
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lushr
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
lxor
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
monenter
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
monexit
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
multianewarray
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
new
"
Create new object
stack: nothing -> objectRef
args: indexByte1 indexByte2"
| classRef result |
classRef := constantPool at: self fetchIndex2.
self breakPoint:#mh_instructions.
result := (JavaVM classForName: classRef name) new.
"
Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index into
the runtime constant pool of the current class (§3.6), where the value of
the index is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item
at the index must be a symbolic reference to a class, array, or interface
type. The named class, array, or interface type is resolved (§5.4.3.1) and
should result in a class type (it should not result in an array or interface
type). Memory for a new instance of that class is allocated from the
garbage-collected heap, and the instance variables of the new object are
initialized to their default initial values (§2.5.1). The objectref, a reference
to the instance, is pushed onto the operand stack.
On successful resolution of the class, it is initialized (§5.5) if it has not
already been initialized.
Linking Exceptions
During resolution of the symbolic reference to the class, array, or interface
type, any of the exceptions documented in Section 5.4.3.1 can be thrown.
Otherwise, if the symbolic reference to the class, array, or interface type
resolves to an interface or is an abstract class, new throws an InstantiationError.
Runtime Exception
Otherwise, if execution of this new instruction causes initialization of the
referenced class, new may throw an Error as detailed in Section 2.17.5.
Note
The new instruction does not completely create a new instance; instance creation
is not completed until an instance initialization method has been invoked on
the uninitialized instance."
"Created: / 25-02-2011 / 00:17:39 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 24-02-2011 / 22:13:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 13-03-2011 / 17:18:17 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
newarray
"
Create new array
stack: count -> arrayRef
args: arrayType"
| type size |
type := self fetchByte.
size := self pop.
type = 4 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'boolean' sized: size ].
type = 5 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'char' sized: size ].
type = 6 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'float' sized: size ].
type = 7 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'double' sized: size ].
type = 8 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'byte' sized: size ].
type = 9 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'short' sized: size ].
type = 10 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'int' sized: size ].
type = 11 ifTrue: [ ^ self pushNewPrimitiveArrayOf: 'long' sized: size ].
self halt: 'Type not recognized - tell mh'.
"
Description
The count must be of type int. It is popped off the operand stack. The count represents
the number of elements in the array to be created.
The atype is a code that indicates the type of array to create. It must take one of the
following values:
Array Type atype
T_BOOLEAN 4
T_CHAR 5
T_FLOAT 6
T_DOUBLE 7
T_BYTE 8
T_SHORT 9
T_INT 10
T_LONG 11
A new array whose components are of type atype and of length count is allocated
from the garbage-collected heap. A reference arrayref to this new array object is pushed
into the operand stack. Each of the elements of the new array is initialized to the
default initial value for the type of the array (§2.5.1).
Runtime Exception
If count is less than zero, newarray throws a NegativeArraySizeException.
Notes
In Sun's implementation of the Java virtual machine, arrays of type boolean (atype
is T_BOOLEAN) are stored as arrays of 8-bit values and are manipulated using the baload
and bastore instructions, instructions that also access arrays of type byte. Other
implementations may implement packed boolean arrays; the baload and bastore instructions
must still be used to access those arrays.
"
"Created: / 14-03-2011 / 18:24:57 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 27-03-2011 / 21:07:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
nop
"Do nothing"
"Created: / 14-03-2011 / 18:52:50 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
pop1
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
pop2
"
Pop the top one or two operand stack values
stack v1: value2 value1 -> nothing where each of value1 and value2 is a value of a category 1 computational type (§3.11.1).
stack v2: value -> nothing where value is a value of a category 2 computational type (§3.11.1).
args: nothing
"
sp := sp - 2.
"
Description
Pop the top one or two values from the operand stack.
"
"Modified: / 13-03-2011 / 17:20:27 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
putfield
"Set field in object
stack: objectRef value -> nothing
args: indexbyte1 indexbyte2"
| newValue fieldOwner fieldref |
newValue := self pop.
fieldOwner := self pop.
fieldref := constantPool at: self fetchIndex2.
fieldref resolve.
fieldOwner instVarAt: fieldref offset put: newValue.
"Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index
into the runtime constant pool of the current class (§3.6), where the value
of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant pool
item at that index must be a symbolic reference to a field (§5.1), which
gives the name and descriptor of the field as well as a symbolic reference
to the class in which the field is to be found. The class of objectref must
not be an array. If the field is protected (§4.6), and it is either a member
of the current class or a member of a superclass of the current class, then
the class of objectref must be either the current class or a subclass of
the current class.
The referenced field is resolved (§5.4.3.2). The type of a value stored
by a putfield instruction must be compatible with the descriptor of the
referenced field (§4.3.2). If the field descriptor type is boolean, byte,
char, short, or int, then the value must be an int. If the field descriptor
type is float, long, or double, then the value must be a float, long, or
double, respectively. If the field descriptor type is a reference type, then
the value must be of a type that is assignment compatible (§2.6.7) with the
field descriptor type. If the field is final, it should be declared in the
current class. Otherwise, an IllegalAccessError is thrown.
The value and objectref are popped from the operand stack. The objectref
must be of type reference. The value undergoes value set conversion (§3.8.3),
resulting in value', and the referenced field in objectref is set to value'.
Linking Exceptions
During resolution of the symbolic reference to the field, any of the
exceptions pertaining to field resolution documented in Section 5.4.3.2 can be thrown.
Otherwise, if the resolved field is a static field, putfield throws
an IncompatibleClassChangeError.
Otherwise, if the field is final, it must be declared in the current
class. Otherwise, an IllegalAccessError is thrown.
Runtime Exception
Otherwise, if objectref is null, the putfield instruction throws a NullPointerException."
"Modified: / 04-06-2011 / 18:14:12 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
putstatic
"
Set static field in class
stack: value -> nothing
args: indexByte1 indexByte2"
| newValue fieldref |
newValue := self pop.
fieldref := constantPool at: self fetchIndex2.
fieldref resolveStatic.
fieldref owner instVarAt: fieldref offset put: newValue.
"
Description
The unsigned indexbyte1 and indexbyte2 are used to construct an index into
the runtime constant pool of the current class (§3.6), where the value of
the index is (indexbyte1 << 8) | indexbyte2. The runtime constant pool
item at that index must be a symbolic reference to a field (§5.1), which
gives the name and descriptor of the field as well as a symbolic reference
to the class or interface in which the field is to be found. The referenced
field is resolved (§5.4.3.2).
On successful resolution of the field the class or interface that declared
the resolved field is initialized (§5.5) if that class or interface has not
already been initialized.
The type of a value stored by a putstatic instruction must be compatible with
the descriptor of the referenced field (§4.3.2). If the field descriptor type
is boolean, byte, char, short, or int, then the value must be an int. If the
field descriptor type is float, long, or double, then the value must be a float,
long, or double, respectively. If the field descriptor type is a reference type,
then the value must be of a type that is assignment compatible (§2.6.7) with
the field descriptor type. If the field is final, it should be declared in
the current class. Otherwise, an IllegalAccessError is thrown.
The value is popped from the operand stack and undergoes value set conversion
(§3.8.3), resulting in value'. The class field is set to value'.
Linking Exceptions
During resolution of the symbolic reference to the class or interface field,
any of the exceptions pertaining to field resolution documented in Section
5.4.3.2 can be thrown.
Otherwise, if the resolved field is not a static (class) field or an interface
field, putstatic throws an IncompatibleClassChangeError.
Otherwise, if the field is final, it must be declared in the current class.
Otherwise, an IllegalAccessError is thrown.
Runtime Exception
Otherwise, if execution of this putstatic instruction causes initialization
of the referenced class or interface, putstatic may throw an Error as detailed
in Section 2.17.5.
Notes
A putstatic instruction may be used only to set the value of an interface field
on the initialization of that field. Interface fields may be assigned to only
once, on execution of an interface variable initialization expression when the
interface is initialized (§2.17.4)."
"Created: / 24-02-2011 / 23:21:16 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 24-02-2011 / 22:14:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 04-06-2011 / 18:14:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
ret
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
ret_w
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
!
return
"Return void from method
stack: nothing -> nothing
args: nothing"
self leaveProcessorWith: nil.
"
Description
The current method must have return type void. If the current method is a synchronized
method, the monitor acquired or reentered on invocation of the method is released or
exited (respectively) as if by execution of a monitorexit instruction. If no exception
is thrown, any values on the operand stack of the current frame (§3.6) are discarded.
The interpreter then returns control to the invoker of the method, reinstating the
frame of the invoker.
Runtime Exceptions
If the current method is a synchronized method and the current thread is not the owner
of the monitor acquired or reentered on invocation of the method, return throws an
IllegalMonitorStateException. This can happen, for example, if a synchronized method
contains a monitorexit instruction, but no monitorenter instruction, on the object on
which the method is synchronized.
Otherwise, if the virtual machine implementation enforces the rules on structured use
of locks described in Section 8.13 and if the first of those rules is violated during
invocation of the current method, then return throws an IllegalMonitorStateException."
"Created: / 24-02-2011 / 11:38:13 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 24-02-2011 / 23:10:54 / Marcel Hlopko <hlopik@gmail.com>"
"Modified: / 13-03-2011 / 17:22:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
saload
self halt
!
sastore
self halt
!
sipush
"pushes a short onto the stack
stack: nothing -> value
args: byte1 byte2"
self pushInt: (self fetchBytes2).
"
Description
The immediate unsigned byte1 and byte2 values are assembled
into an intermediate short where the value of the short is (byte1 << 8) | byte2.
The intermediate value is then sign-extended to an int value. That value is
pushed onto the operand stack."
"Modified: / 17-03-2011 / 17:03:05 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
swap
"
Swap the top two operand stack values
stack: value2 value1 -> value1 value2
args: nothing
"
| v1 v2 |
v1 := self pop.
v2 := self pop.
self pushInt: v1.
self pushInt: v2.
"
Description
Swap the top two values on the operand stack.
The swap instruction must not be used unless value1 and value2 are both
values of a category 1 computational type (§3.11.1).
Notes
The Java virtual machine does not provide an instruction implementing a
swap on operands of category 2 computational types.
"
"Modified: / 13-03-2011 / 17:24:26 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
tableswtch
"
Access jump table by index and jump
stack: index -> ..
args: insane :)"
| index jmpDest default low high result |
index := self pop asInteger.
self skipPadding.
default := self fetchBytes4.
low := self fetchBytes4.
high := self fetchBytes4.
low to: high
do:
[:idx |
idx = index
ifTrue: [ jmpDest := self fetchBytes4 ]
ifFalse: [ self fetchBytes4 ] ].
jmpDest ifNil: [ jmpDest := default. ].
self relativeJump: jmpDest.
"
Description
A tableswitch is a variable-length instruction. Immediately after the tableswitch opcode,
between 0 and 3 null bytes (zeroed bytes, not the null object) are inserted as padding.
The number of null bytes is chosen so that the following byte begins at an address that
is a multiple of 4 bytes from the start of the current method (the opcode of its first
instruction). Immediately after the padding follow bytes constituting three signed 32-bit
values: default, low, and high. Immediately following those bytes are bytes constituting a
series of high - low + 1 signed 32-bit offsets. The value low must be less than or equal
to high. The high - low + 1 signed 32-bit offsets are treated as a 0-based jump table.
Each of these signed 32-bit values is constructed as (byte1 << 24) | (byte2 << 16) |
(byte3 << 8) | byte4.
The index must be of type int and is popped from the operand stack. If index is less than
low or index is greater than high, then a target address is calculated by adding default
to the address of the opcode of this tableswitch instruction. Otherwise, the offset at
position index - low of the jump table is extracted. The target address is calculated by
adding that offset to the address of the opcode of this tableswitch instruction. Execution
then continues at the target address.
The target address that can be calculated from each jump table offset, as well as the ones
that can be calculated from default, must be the address of an opcode of an instruction
within the method that contains this tableswitch instruction.
Notes
The alignment required of the 4-byte operands of the tableswitch instruction guarantees 4-byte
alignment of those operands if and only if the method that contains the tableswitch starts
on a 4-byte boundary."
"Modified: / 21-03-2011 / 18:35:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
wide
"raise an error: must be redefined in concrete subclass(es)"
^ self shouldImplement
! !
!JavaByteCodeInterpreter methodsFor:'interpretation'!
handleAbstractMethod
self halt: 'Is it allowed to interpret abstract method? I dont think so :)'.
"Created: / 22-03-2011 / 14:50:44 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
interpret: aMethod receiver: aReceiver arguments: args
self
log: ('Invoking method ' , aMethod name , ' on ' , aReceiver printString
, ' with ' , args printString).
^ self
process: aMethod
receiver: aReceiver
arguments: args.
"Created: / 17-03-2011 / 17:25:01 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 28-03-2011 / 18:03:17 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
interpretInner: aJavaMethod receiver: aReceiver arguments: anArgs
^ aJavaMethod interpretWithReceiver: aReceiver arguments: anArgs.
"Created: / 31-03-2011 / 16:29:37 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !
!JavaByteCodeInterpreter class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libjava/Attic/JavaByteCodeInterpreter.st,v 1.3 2011-11-24 11:54:55 cg Exp $'
!
version_CVS
^ '$Header: /cvs/stx/stx/libjava/Attic/JavaByteCodeInterpreter.st,v 1.3 2011-11-24 11:54:55 cg Exp $'
!
version_SVN
^ '§Id: JavaByteCodeInterpreter.st,v 1.1 2011/08/18 19:06:53 vrany Exp §'
! !