--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/experiments/JavaByteCodeInterpreter.st Thu Nov 15 22:10:02 2012 +0000
@@ -0,0 +1,2991 @@
+"
+ COPYRIGHT (c) 1996-2011 by Claus Gittinger
+
+ New code and modifications done at SWING Research Group [1]:
+
+ COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
+ SWING Research Group, Czech Technical University in Prague
+
+ 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.
+
+ [1] Code written at SWING Research Group contains a signature
+ of one of the above copright owners. For exact set of such code,
+ see the differences between this version and version stx:libjava
+ as of 1.9.2010
+"
+"{ Package: 'stx:libjava/experiments' }"
+
+JavaByteCodeProcessor subclass:#JavaByteCodeInterpreter
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Languages-Java-Bytecode'
+!
+
+!JavaByteCodeInterpreter class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1996-2011 by Claus Gittinger
+
+ New code and modifications done at SWING Research Group [1]:
+
+ COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
+ SWING Research Group, Czech Technical University in Prague
+
+ 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.
+
+ [1] Code written at SWING Research Group contains a signature
+ of one of the above copright owners. For exact set of such code,
+ see the differences between this version and version stx:libjava
+ as of 1.9.2010
+
+"
+! !
+
+!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 |
+ self breakPoint: #mh.
+ 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 resolve.
+ 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: / 08-12-2011 / 19:24:33 / 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 resolve.
+ 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: / 08-12-2011 / 19:24:38 / 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_SVN
+ ^ '$Id$'
+! !