Skip to content

Commit

Permalink
JACOBIN-592 Implemented LDC and LDC_W bytecodes, plus minor code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
platypusguy committed Oct 19, 2024
1 parent f4df78a commit 711d589
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/config/buildno.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@

package config

var BuildNo = 3075
var BuildNo = 3077
3 changes: 3 additions & 0 deletions src/exceptions/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ import (
"jacobin/globals"
"jacobin/log"
"jacobin/thread"
"math"
"runtime/debug"
"strings"
)

var ERROR_OCCURRED = math.MaxInt32

// routines for formatting error data when an error occurs inside the JVM

// Prints out the frame stack
Expand Down
91 changes: 71 additions & 20 deletions src/jvm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"jacobin/statics"
"jacobin/stringPool"
"jacobin/types"
"jacobin/util"
"runtime/debug"
)

Expand Down Expand Up @@ -54,9 +55,9 @@ var DispatchTable = [203]BytecodeFunc{
doDconst1, // DCONST_1 0x0F
doBiPush, // BIPUSH 0x10
notImplemented, // SIPUSH 0x11
notImplemented, // LDC 0x12
notImplemented, // LDC_W 0x13
notImplemented, // LDC2_W 0x14
doLdc, // LDC 0x12
doLdcw, // LDC_W 0x13
notImplemented, // LDC2_W 0x14
notImplemented, // ILOAD 0x15
notImplemented, // LLOAD 0x16
notImplemented, // FLOAD 0x17
Expand Down Expand Up @@ -241,6 +242,7 @@ var DispatchTable = [203]BytecodeFunc{
notImplemented, // BREAKPOINT 0xCA
}

// the main interpreter loop
func interpret(fs *list.List) {
fr := fs.Front().Value.(*frames.Frame)
if fr.FrameStack == nil { // make sure the can reference the frame stack
Expand All @@ -254,18 +256,24 @@ func interpret(fs *list.List) {
}

opcode := fr.Meth[fr.PC]
fr.PC += DispatchTable[opcode](fr, 0)
ret := DispatchTable[opcode](fr, 0)
if ret == exceptions.ERROR_OCCURRED { // occurs only in tests
break
} else {
fr.PC += ret
}
}
}

// the functions, listed here in numerical order of the bytecode
func doNop(_ *frames.Frame, _ int64) int { return 1 }
func doNop(_ *frames.Frame, _ int64) int { return 1 } // 0x00

func doAconstNull(fr *frames.Frame, _ int64) int {
func doAconstNull(fr *frames.Frame, _ int64) int { // 0x01 ACONST_NULL push null onto stack
push(fr, object.Null)
return 1
}

// 0x02 - 0x0A ICONST and LCONST, push int or long onto stack
func doIconstM1(fr *frames.Frame, _ int64) int { return pushInt(fr, int64(-1)) }
func doIconst0(fr *frames.Frame, _ int64) int { return pushInt(fr, int64(0)) }
func doIconst1(fr *frames.Frame, _ int64) int { return pushInt(fr, int64(1)) }
Expand All @@ -281,13 +289,18 @@ func doFconst2(fr *frames.Frame, _ int64) int { return pushFloat(fr, int64(2))
func doDconst0(fr *frames.Frame, _ int64) int { return pushFloat(fr, int64(0)) }
func doDconst1(fr *frames.Frame, _ int64) int { return pushFloat(fr, int64(1)) }

func doBiPush(fr *frames.Frame, _ int64) int {
func doBiPush(fr *frames.Frame, _ int64) int { // 0x10 BIPUSH push following byte onto stack
wbyte := fr.Meth[fr.PC+1]
wint64 := byteToInt64(wbyte)
push(fr, wint64)
return 2
}

// 0x12, 0x13 LDC functions
func doLdc(fr *frames.Frame, _ int64) int { return ldc(fr, 1) }
func doLdcw(fr *frames.Frame, _ int64) int { return ldc(fr, 2) }

// 0x3B - 0x3E ISTORE_0 thru _3: Store popped TOS into locals specified as 0-3 in bytecode name
func doIstore0(fr *frames.Frame, _ int64) int { return storeInt(fr, int64(0)) }
func doIstore1(fr *frames.Frame, _ int64) int { return storeInt(fr, int64(1)) }
func doIstore2(fr *frames.Frame, _ int64) int { return storeInt(fr, int64(2)) }
Expand All @@ -298,7 +311,7 @@ func doIload1(fr *frames.Frame, _ int64) int { return loadInt(fr, int64(1)) }
func doIload2(fr *frames.Frame, _ int64) int { return loadInt(fr, int64(2)) }
func doIload3(fr *frames.Frame, _ int64) int { return loadInt(fr, int64(3)) }

func doIfIcmpge(fr *frames.Frame, _ int64) int {
func doIfIcmpge(fr *frames.Frame, _ int64) int { // 0xA2 IF_ICMPGE Compare ints for >=
popValue := pop(fr)
val2 := convertInterfaceToInt64(popValue)
popValue = pop(fr)
Expand Down Expand Up @@ -396,7 +409,56 @@ func notImplemented(_ *frames.Frame, _ int64) int {
return 1
}

// the functions call by the dispatched functions
// === helper methods--that is, functions called by dispatched methods (in alpha order) ===

func loadInt(fr *frames.Frame, local int64) int {
push(fr, fr.Locals[local])
return 1
}

func ldc(fr *frames.Frame, width int) int {
var idx int
if width == 1 { // LDC uses a 1-byte index into the CP, LDC_W uses a 2-byte index
idx = int(fr.Meth[fr.PC+1])
} else {
idx = (int(fr.Meth[fr.PC+1]) * 256) + int(fr.Meth[fr.PC+2])
}

CPe := classloader.FetchCPentry(fr.CP.(*classloader.CPool), idx)
if CPe.EntryType == 0 || // 0 = error
// Note: an invalid CP entry causes a java.lang.Verify error and
// is caught before execution of the program begins.
// This bytecode does not load longs or doubles
CPe.EntryType == classloader.DoubleConst ||
CPe.EntryType == classloader.LongConst {
globals.GetGlobalRef().ErrorGoStack = string(debug.Stack())
errMsg := fmt.Sprintf("in %s.%s, LDC: Invalid type for bytecode operand",
util.ConvertInternalClassNameToUserFormat(fr.ClName), fr.MethName)
status := exceptions.ThrowEx(excNames.ClassFormatError, errMsg, fr)
if status != exceptions.Caught {
return exceptions.ERROR_OCCURRED // applies only if in test
}
}
// if no error
switch CPe.RetType {
case classloader.IS_INT64:
push(fr, CPe.IntVal)
case classloader.IS_FLOAT64:
push(fr, CPe.FloatVal)
case classloader.IS_STRUCT_ADDR:
push(fr, CPe.AddrVal)
case classloader.IS_STRING_ADDR: // returns a string object whose "value" field is a byte array
stringAddr := object.StringObjectFromGoString(*CPe.StringVal)
push(fr, stringAddr)
}

if width == 1 {
return 2 // 1 for the index + 1 for the next bytecode
} else {
return 3 // 2 for the index + 1 for the next bytecode
}
}

func pushInt(fr *frames.Frame, intToPush int64) int {
push(fr, intToPush)
return 1
Expand All @@ -411,14 +473,3 @@ func storeInt(fr *frames.Frame, local int64) int {
fr.Locals[local] = pop(fr)
return 1
}

func loadInt(fr *frames.Frame, local int64) int {
push(fr, fr.Locals[local])
return 1
}

func interpretBytecodes(bytecode int, f *frames.Frame) int {
PC := DispatchTable[bytecode](f, 0)
println("PC after call to DispatchTable[", bytecode, "] = ", PC)
return PC
}
1 change: 0 additions & 1 deletion src/wholeClassTests/Hello1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import (
* line 5: 16
* line 7: 22
*
*
* These tests check the output with various options for verbosity and features set on the command line.
*/

Expand Down

0 comments on commit 711d589

Please sign in to comment.