Skip to content

Commit bc0148c

Browse files
committed
Refactor method execution to be cleaner.
1 parent 3e30c8e commit bc0148c

File tree

10 files changed

+164
-121
lines changed

10 files changed

+164
-121
lines changed

Main.class

16 Bytes
Binary file not shown.

Main.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public int premultiply(int c) {
1515

1616
public static void main(String[] args) {
1717
Main main = new Main();
18-
int d = main.premultiply(2);
18+
int d = main.premultiply(2) * add(1,2);
1919
}
2020

2121
}

attribute.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type CodeAttribute struct {
2323
attributes []Attribute
2424
}
2525

26-
func (codeAttribute *CodeAttribute) toFrame(class Class, args ...interface{}) Frame {
26+
func (codeAttribute *CodeAttribute) toFrame(class *Class, args ...interface{}) Frame {
2727

2828
frame := Frame{
2929
code: codeAttribute.code,
@@ -39,13 +39,13 @@ func (codeAttribute *CodeAttribute) toFrame(class Class, args ...interface{}) Fr
3939
return frame
4040
}
4141

42-
func (attribute *Attribute) toCodeAttribute() CodeAttribute {
42+
func (attribute *Attribute) toCodeAttribute() *CodeAttribute {
4343
codeAttribute := CodeAttribute{
4444
name: attribute.name,
4545
maxStack: binary.BigEndian.Uint16(attribute.info[0:2]),
4646
maxLocals: binary.BigEndian.Uint16(attribute.info[2:4]),
4747
}
4848
codeLength := binary.BigEndian.Uint32(attribute.info[4:8])
4949
codeAttribute.code = attribute.info[8 : 8+codeLength]
50-
return codeAttribute
50+
return &codeAttribute
5151
}

class.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package main
22

3+
import "errors"
4+
35
type u1 = uint8
46
type u2 = uint16
57
type u4 = uint32
@@ -23,11 +25,11 @@ type Interface struct {
2325
name string
2426
}
2527

26-
func (class *Class) findMethod(name string) Method {
28+
func (class *Class) findMethod(name string, descriptor string) (*Method, error) {
2729
for i := 0; i < len(class.methods); i++ {
28-
if class.methods[i].name == name {
29-
return class.methods[i]
30+
if class.methods[i].name == name && class.methods[i].descriptor == descriptor {
31+
return &class.methods[i], nil
3032
}
3133
}
32-
panic("method not found")
34+
return nil, errors.New("method not found " + name)
3335
}

constant_pool.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type MethodRef struct {
3434
type MethodRefResolved struct {
3535
class string
3636
name string
37-
methodType string
37+
descriptor string
3838
}
3939

4040
type FieldRef = MethodRef
@@ -81,7 +81,7 @@ func (constantPool ConstantPool) resolveFieldRef(index u2) FieldRefResolved {
8181

8282
nameAndType := constantPool[methodRef.NameAndTypeIndex-1].info.NameAndType
8383
methodRefResolved.name = constantPool.resolveString(nameAndType.nameIndex)
84-
methodRefResolved.methodType = constantPool.resolveString(nameAndType.descriptor)
84+
methodRefResolved.descriptor = constantPool.resolveString(nameAndType.descriptor)
8585

8686
return methodRefResolved
8787

@@ -108,7 +108,7 @@ func (constantPool ConstantPool) resolveMethodRef(index u2) MethodRefResolved {
108108

109109
nameAndType := constantPool[methodRef.NameAndTypeIndex-1].info.NameAndType
110110
methodRefResolved.name = constantPool.resolveString(nameAndType.nameIndex)
111-
methodRefResolved.methodType = constantPool.resolveString(nameAndType.descriptor)
111+
methodRefResolved.descriptor = constantPool.resolveString(nameAndType.descriptor)
112112

113113
return methodRefResolved
114114

fields.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package main
22

3+
import "strings"
4+
35
type Field struct {
46
accessFlags u2
57
name string
@@ -8,12 +10,34 @@ type Field struct {
810
value interface{}
911
}
1012

11-
type Method Field
13+
type Method struct {
14+
accessFlags u2
15+
name string
16+
descriptor string
17+
attributes []Attribute
18+
value interface{}
19+
}
20+
type MethodDescriptorDetailed struct {
21+
params string
22+
returnType string
23+
}
24+
25+
func findMethodDescriptorDetailed(descriptor string) (*MethodDescriptorDetailed, error) {
26+
start := strings.Index(descriptor, "(")
27+
end := strings.Index(descriptor, ")")
28+
29+
params := descriptor[start+1 : end]
30+
returnTypes := descriptor[end+1:]
31+
return &MethodDescriptorDetailed{
32+
params: params,
33+
returnType: returnTypes,
34+
}, nil
35+
}
1236

13-
func (method *Method) findCodeAttribute() CodeAttribute {
37+
func (method Method) findCodeAttribute() (*CodeAttribute, error) {
1438
for _, attribute := range method.attributes {
1539
if attribute.name == "Code" {
16-
return attribute.toCodeAttribute()
40+
return attribute.toCodeAttribute(), nil
1741
}
1842
}
1943
panic("not a code attribute")

frame.go

Lines changed: 66 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ package main
33
import (
44
"fmt"
55
"os"
6-
"strings"
76
)
87

98
type Frame struct {
10-
operandStack []interface{}
9+
stack []interface{}
1110
localVariables []interface{} // function parameters basically
1211
code []byte
1312
instructionPointer uint32
14-
class Class
13+
class *Class
1514
}
1615

17-
func (frame *Frame) Exec() interface{} {
16+
func (frame *Frame) getIndex() u2 {
17+
indexByte1 := frame.code[frame.instructionPointer+1]
18+
indexByte2 := frame.code[frame.instructionPointer+2]
19+
frame.instructionPointer = frame.instructionPointer + 2
20+
return (u2(indexByte1) << 8) | u2(indexByte2)
21+
}
22+
23+
func (jvm *JVM) Exec(frame *Frame) interface{} {
1824

1925
for {
2026
op := frame.code[frame.instructionPointer]
@@ -23,52 +29,52 @@ func (frame *Frame) Exec() interface{} {
2329
case 0: // noop
2430

2531
case 4: // iconst_1
26-
frame.operandStack = append(frame.operandStack, 1)
32+
frame.stack = append(frame.stack, 1)
2733
case 5: // iconst_2
28-
frame.operandStack = append(frame.operandStack, 2)
34+
frame.stack = append(frame.stack, 2)
2935
case 6: // iconst_3
30-
frame.operandStack = append(frame.operandStack, 3)
36+
frame.stack = append(frame.stack, 3)
3137
case 7: // iconst_4
32-
frame.operandStack = append(frame.operandStack, 4)
38+
frame.stack = append(frame.stack, 4)
3339
case 17: // sipush
3440
case 26: // iload_0
35-
frame.operandStack = append(frame.operandStack, frame.localVariables[0])
41+
frame.stack = append(frame.stack, frame.localVariables[0])
3642
case 27: // iload_1
37-
frame.operandStack = append(frame.operandStack, frame.localVariables[1])
43+
frame.stack = append(frame.stack, frame.localVariables[1])
3844
case 42: // aload0
39-
frame.operandStack = append(frame.operandStack, frame.localVariables[0])
45+
frame.stack = append(frame.stack, frame.localVariables[0])
4046
case 43: // aload1
41-
frame.operandStack = append(frame.operandStack, frame.localVariables[1])
47+
frame.stack = append(frame.stack, frame.localVariables[1])
4248
case 60: // istore_1
43-
last := frame.operandStack[len(frame.operandStack)-1].(int)
44-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
49+
last := frame.stack[len(frame.stack)-1].(int)
50+
frame.stack = frame.stack[:len(frame.stack)-1]
4551
frame.localVariables[1] = last
4652
case 61: // istore2
47-
last := frame.operandStack[len(frame.operandStack)-1].(int)
48-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
53+
last := frame.stack[len(frame.stack)-1].(int)
54+
frame.stack = frame.stack[:len(frame.stack)-1]
4955
frame.localVariables[2] = last
5056
case 76: // astore_1
51-
last := frame.operandStack[len(frame.operandStack)-1]
52-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
57+
last := frame.stack[len(frame.stack)-1]
58+
frame.stack = frame.stack[:len(frame.stack)-1]
5359
frame.localVariables[1] = last
5460
case 87: // pop
55-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
61+
frame.stack = frame.stack[:len(frame.stack)-1]
5662
case 89: // dup
57-
last := frame.operandStack[len(frame.operandStack)-1]
58-
frame.operandStack = append(frame.operandStack, last)
63+
last := frame.stack[len(frame.stack)-1]
64+
frame.stack = append(frame.stack, last)
5965
case 96: // iadd
60-
first := frame.operandStack[len(frame.operandStack)-1].(int)
61-
second := frame.operandStack[len(frame.operandStack)-2].(int)
62-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-2]
63-
frame.operandStack = append(frame.operandStack, first+second)
66+
first := frame.stack[len(frame.stack)-1].(int)
67+
second := frame.stack[len(frame.stack)-2].(int)
68+
frame.stack = frame.stack[:len(frame.stack)-2]
69+
frame.stack = append(frame.stack, first+second)
6470
case 104: // imul
6571
first := frame.pop().(int)
6672
second := frame.pop().(int)
67-
frame.operandStack = append(frame.operandStack, first*second)
73+
frame.stack = append(frame.stack, first*second)
6874
case 172: // ireturn
69-
return nil
75+
return frame.pop()
7076
case 177: // return
71-
frame.operandStack = append(frame.operandStack, nil)
77+
frame.stack = append(frame.stack, nil)
7278
return nil
7379
case 180: // getField
7480
frame.instructionPointer++
@@ -77,10 +83,10 @@ func (frame *Frame) Exec() interface{} {
7783
indexByte2 := frame.code[frame.instructionPointer]
7884
_ = (indexByte1 << 8) | indexByte2
7985

80-
objectRef := frame.pop().(Class)
86+
objectRef := frame.pop().(*Class)
8187
frame.push(objectRef.fields[0].value)
82-
//frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
83-
//frame.operandStack = append(frame.operandStack, frame.class.constantPool.resolveFieldRef(u2(fieldRefIndex)))
88+
//frame.stack = frame.stack[:len(frame.stack)-1]
89+
//frame.stack = append(frame.stack, frame.class.constantPool.resolveFieldRef(u2(fieldRefIndex)))
8490
case 181: // putField
8591
frame.instructionPointer++
8692
indexByte1 := frame.code[frame.instructionPointer]
@@ -89,85 +95,45 @@ func (frame *Frame) Exec() interface{} {
8995
_ = (indexByte1 << 8) | indexByte2
9096

9197
value := frame.pop().(int)
92-
objectRef := frame.pop().(Class)
98+
objectRef := frame.pop().(*Class)
9399

94100
objectRef.fields[0].value = value
95-
case 182, 183: // invokespecial
96-
frame.instructionPointer++
97-
indexByte1 := frame.code[frame.instructionPointer]
98-
frame.instructionPointer++
99-
indexByte2 := frame.code[frame.instructionPointer]
100-
methodRefIndex := (indexByte1 << 8) | indexByte2
101-
102-
resolved := frame.class.constantPool.resolveMethodRef(u2(methodRefIndex))
103-
104-
// now we need to execute this again
105-
var method Method
106-
if resolved.class == frame.class.name {
107-
method = frame.class.findMethod(resolved.name)
108-
109-
start := strings.Index(resolved.methodType, "(")
110-
end := strings.Index(resolved.methodType, ")")
111-
params := resolved.methodType[start+1 : end]
112-
returnTypes := resolved.methodType[end+1:]
113-
114-
methodCodeAttribute := method.findCodeAttribute()
115-
args := make([]interface{}, 0)
116-
for _ = range len(params) {
117-
arg := frame.operandStack[len(frame.operandStack)-1]
118-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
119-
args = append(args, arg)
120-
}
121-
objectRef := frame.operandStack[len(frame.operandStack)-1]
122-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
123-
args = append([]interface{}{objectRef.(Class)}, args...)
124-
125-
methodFrame := methodCodeAttribute.toFrame(objectRef.(Class), args...)
126-
methodFrame.Exec()
127-
128-
if len(returnTypes) != 0 && returnTypes != "V" {
129-
frame.operandStack = append(frame.operandStack, methodFrame.operandStack[len(methodFrame.operandStack)-1])
130-
}
131-
132-
} else if resolved.class == "java/lang/Object" {
133-
} else {
134-
panic("we do not know this class")
101+
case 182, 183: // invokespecial, invokeVirtual
102+
methodRefIndex := frame.getIndex()
103+
methodRef := frame.class.constantPool.resolveMethodRef(methodRefIndex)
104+
105+
methodDescriptorDetailed, _ := findMethodDescriptorDetailed(methodRef.descriptor)
106+
params, returnType := methodDescriptorDetailed.params, methodDescriptorDetailed.returnType
107+
args := frame.stack[len(frame.stack)-len(params)-1:]
108+
frame.stack = frame.stack[:len(frame.stack)-len(params)-1]
109+
110+
result, err := jvm.executeMethod(methodRef.class, methodRef.name, methodRef.descriptor, args...)
111+
if err != nil {
112+
return nil
135113
}
136114

137-
fmt.Printf("%d", methodRefIndex)
115+
if len(returnType) != 0 && returnType != "V" {
116+
frame.stack = append(frame.stack, result)
117+
}
138118

139119
case 184: // (0xb8) invokestatic
140-
frame.instructionPointer++
141-
indexByte1 := frame.code[frame.instructionPointer]
142-
frame.instructionPointer++
143-
indexByte2 := frame.code[frame.instructionPointer]
144-
methodRefIndex := (indexByte1 << 8) | indexByte2
120+
methodRefIndex := frame.getIndex()
121+
methodRef := frame.class.constantPool.resolveMethodRef(methodRefIndex)
145122

146-
resolved := frame.class.constantPool.resolveMethodRef(u2(methodRefIndex))
123+
methodDescriptorDetailed, _ := findMethodDescriptorDetailed(methodRef.descriptor)
124+
params, returnType := methodDescriptorDetailed.params, methodDescriptorDetailed.returnType
125+
args := frame.stack[len(frame.stack)-len(params):]
126+
frame.stack = frame.stack[:len(frame.stack)-len(params)]
147127

148-
// now we need to execute this again
149-
method := frame.class.findMethod(resolved.name)
150-
151-
// the variables are already on the stack, does the internal stack get passed along????
152-
153-
start := strings.Index(resolved.methodType, "(")
154-
end := strings.Index(resolved.methodType, ")")
155-
params := resolved.methodType[start+1 : end]
156-
returnTypes := resolved.methodType[end+1:]
157-
158-
methodCodeAttribute := method.findCodeAttribute()
159-
args := make([]interface{}, 0)
160-
for _ = range len(params) {
161-
arg := frame.operandStack[len(frame.operandStack)-1]
162-
frame.operandStack = frame.operandStack[:len(frame.operandStack)-1]
163-
args = append(args, arg)
128+
result, err := jvm.executeMethod(methodRef.class, methodRef.name, methodRef.descriptor, args...)
129+
if err != nil {
130+
return nil
164131
}
165-
methodFrame := methodCodeAttribute.toFrame(frame.class, args...)
166-
methodFrame.Exec()
167132

168-
if len(returnTypes) != 0 && returnTypes != "V" {
169-
frame.operandStack = append(frame.operandStack, methodFrame.operandStack[len(methodFrame.operandStack)-1])
133+
if len(returnType) != 0 && returnType != "V" {
134+
frame.stack = append(frame.stack, result)
170135
}
136+
171137
case 187: // new
172138
frame.instructionPointer++
173139
indexByte1 := frame.code[frame.instructionPointer]
@@ -181,7 +147,7 @@ func (frame *Frame) Exec() interface{} {
181147
loader := &ClassLoader{reader: file}
182148

183149
newClass := loader.loadClass()
184-
frame.operandStack = append(frame.operandStack, newClass)
150+
frame.stack = append(frame.stack, &newClass)
185151

186152
default:
187153
fmt.Printf("wooops unimplemented op code %d\n", op)

0 commit comments

Comments
 (0)