Skip to content

56 implement tableswitch and lookuptable insts #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 63 additions & 58 deletions src/execution/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::rc::Rc;
use std::sync::{Mutex};
use crate::core::method_area::{Method, RuntimeClass};
use crate::core::stack_area::{LocalVariable, StackFrame, Thread};
use crate::error;
use num_traits::FromPrimitive;
use crate::{error, log};
use num_traits::{FromPrimitive, ToPrimitive};
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
use crate::classloader::attributes::AttributeInfo;
Expand Down Expand Up @@ -732,9 +732,9 @@ pub fn interpret(thread: &mut Thread, frame: Rc<StackFrame>, class: Rc<RuntimeCl
}

Some(Opcode::Bipush) => {
let value = code[*frame.pc.read().unwrap() + 1] as i32;
let value = code[*frame.pc.read().unwrap() + 1] as i8;
*frame.pc.write().unwrap() += 1;
push!(Value::Int(value));
push!(Value::Int(value.to_i32().unwrap()));
}

Some(Opcode::Sipush) => {
Expand Down Expand Up @@ -2037,71 +2037,76 @@ pub fn interpret(thread: &mut Thread, frame: Rc<StackFrame>, class: Rc<RuntimeCl
continue;
}

// TODO: TableSwitch and LookupSwitch Instructions may be incorrect...
Some(Opcode::TableSwitch) => {
let mut pc_offset = 1;
while (*frame.pc.read().unwrap() + pc_offset) % 4 != 0 {
pc_offset += 1;
}
let default_offset = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
let low = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
let high = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
let mut jump_offsets = Vec::new();
for _ in 0..(high - low + 1) {
let jump_offset = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
jump_offsets.push(jump_offset);
let base_pc = *frame.pc.read().unwrap();

while (*frame.pc.read().unwrap() + 1) % 4 != 0 {
*frame.pc.write().unwrap() += 1;
}

let value = pop!().unwrap();
match value {
Value::Int(v) => {
if v < low || v > high {
*frame.pc.write().unwrap() += default_offset as usize;
} else {
*frame.pc.write().unwrap() += jump_offsets[(v - low) as usize] as usize;
}
}
_ => {
error("Invalid operand type for TableSwitch");
}
let default_offset = read_int!();
*frame.pc.write().unwrap() += 4;

let low = read_int!() as i32;
*frame.pc.write().unwrap() += 4;
let high = read_int!() as i32;
*frame.pc.write().unwrap() += 4;

let Value::Int(index) = pop!().unwrap() else {
error("Invalid operand type for LookupSwitch");
panic!();
};

if index < low || index > high {
*frame.pc.write().unwrap() = base_pc + default_offset;
continue;
}

*frame.pc.write().unwrap() += 4 * (index - low).to_usize().unwrap();

let offset = read_int!();
*frame.pc.write().unwrap() = base_pc + offset;
continue;
}

Some(Opcode::LookupSwitch) => {
let mut pc_offset = 1;
while (*frame.pc.read().unwrap() + pc_offset) % 4 != 0 {
pc_offset += 1;
}
let default_offset = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
let npairs = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
let mut match_offsets = HashMap::new();
for _ in 0..npairs {
let match_value = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
let jump_offset = ((code[*frame.pc.read().unwrap() + pc_offset] as i32) << 24) | ((code[*frame.pc.read().unwrap() + pc_offset + 1] as i32) << 16) | ((code[*frame.pc.read().unwrap() + pc_offset + 2] as i32) << 8) | code[*frame.pc.read().unwrap() + pc_offset + 3] as i32;
pc_offset += 4;
match_offsets.insert(match_value, jump_offset);
let base_pc = *frame.pc.read().unwrap();

while (*frame.pc.read().unwrap() + 1) % 4 != 0 {
*frame.pc.write().unwrap() += 1;
}

let value = pop!().unwrap();
match value {
Value::Int(v) => {
if !match_offsets.contains_key(&v) {
*frame.pc.write().unwrap() += default_offset as usize;
} else {
*frame.pc.write().unwrap() += match_offsets[&v] as usize;
}
}
_ => {
error("Invalid operand type for LookupSwitch");
let default_offset = read_int!();
*frame.pc.write().unwrap() += 4;

let npairs = read_int!();
*frame.pc.write().unwrap() += 4;

let Value::Int(key) = pop!().unwrap() else {
error("Invalid operand type for LookupSwitch");
panic!();
};

let mut matched = false;
for _ in 0..npairs {
let match_value = read_int!() as i32;
*frame.pc.write().unwrap() += 4;
let offset = read_int!();
*frame.pc.write().unwrap() += 4;

if key == match_value {
*frame.pc.write().unwrap() = base_pc + offset;
matched = true;
break;
}
}

if matched {
continue;
}

*frame.pc.write().unwrap() = base_pc + default_offset;
continue;
}

Some(Opcode::IReturn) => {
Expand Down
Binary file modified web/public/java/Logic.class
Binary file not shown.
21 changes: 21 additions & 0 deletions web/public/java/Logic.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
class Logic {
public static void main(String[] args) {
int a = -2;
switch (a) {
case -2:
a = -20;
break;
case 0:
a = 0;
break;
case 1:
a = 10;
break;
case 2:
a = 20;
break;
case 4:
a = 40;
break;
default:
a = 100;
}

int[] test = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
if (i == 0) {
Expand Down
182 changes: 117 additions & 65 deletions web/public/java/Logic.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Classfile /Users/itsuru/RustroverProjects/bjvm/web/public/java/Logic.class
Last modified 2024/08/20; size 403 bytes
SHA-256 checksum 32efcdc2d601cb649d2e57abbd40214bd7f13b46e6dc7156d0512b5e843251b0
Last modified 2024/08/21; size 541 bytes
SHA-256 checksum 784a826aef995f46bd078927d3acc43f4ef70efd6400ebf5aa00c665fe76720e
Compiled from "Logic.java"
class Logic
minor version: 0
Expand Down Expand Up @@ -43,72 +43,124 @@ Constant pool:
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=3, args_size=1
0: iconst_5
1: newarray int
3: dup
4: iconst_0
5: iconst_1
6: iastore
7: dup
8: iconst_1
9: iconst_2
10: iastore
11: dup
12: iconst_2
13: iconst_3
14: iastore
15: dup
16: iconst_3
17: iconst_4
18: iastore
19: dup
20: iconst_4
21: iconst_5
22: iastore
23: astore_1
24: iconst_0
25: istore_2
26: iload_2
27: iconst_5
28: if_icmpge 67
31: iload_2
32: ifne 37
35: aconst_null
36: astore_1
37: iload_2
38: iconst_1
39: if_icmpne 61
42: aload_1
43: ifnonnull 53
46: iconst_0
47: newarray int
49: astore_1
50: goto 61
53: iconst_1
54: newarray int
56: dup
57: iconst_0
58: iconst_1
59: iastore
60: astore_1
61: iinc 2, 1
64: goto 26
67: return
stack=4, locals=4, args_size=1
0: iconst_4
1: istore_1
2: iload_1
3: tableswitch { // -2 to 4
-2: 44
-1: 73
0: 50
1: 55
2: 61
3: 73
4: 67
default: 73
}
44: bipush -20
46: istore_1
47: goto 76
50: iconst_0
51: istore_1
52: goto 76
55: bipush 10
57: istore_1
58: goto 76
61: bipush 20
63: istore_1
64: goto 76
67: bipush 40
69: istore_1
70: goto 76
73: bipush 100
75: istore_1
76: iconst_5
77: newarray int
79: dup
80: iconst_0
81: iconst_1
82: iastore
83: dup
84: iconst_1
85: iconst_2
86: iastore
87: dup
88: iconst_2
89: iconst_3
90: iastore
91: dup
92: iconst_3
93: iconst_4
94: iastore
95: dup
96: iconst_4
97: iconst_5
98: iastore
99: astore_2
100: iconst_0
101: istore_3
102: iload_3
103: iconst_5
104: if_icmpge 143
107: iload_3
108: ifne 113
111: aconst_null
112: astore_2
113: iload_3
114: iconst_1
115: if_icmpne 137
118: aload_2
119: ifnonnull 129
122: iconst_0
123: newarray int
125: astore_2
126: goto 137
129: iconst_1
130: newarray int
132: dup
133: iconst_0
134: iconst_1
135: iastore
136: astore_2
137: iinc 3, 1
140: goto 102
143: return
LineNumberTable:
line 3: 0
line 4: 24
line 5: 31
line 6: 35
line 8: 37
line 9: 42
line 10: 46
line 12: 53
line 4: 61
line 16: 67
StackMapTable: number_of_entries = 5
line 4: 2
line 6: 44
line 7: 47
line 9: 50
line 10: 52
line 12: 55
line 13: 58
line 15: 61
line 16: 64
line 18: 67
line 19: 70
line 21: 73
line 24: 76
line 25: 100
line 26: 107
line 27: 111
line 29: 113
line 30: 118
line 31: 122
line 33: 129
line 25: 137
line 37: 143
StackMapTable: number_of_entries = 12
frame_type = 252 /* append */
offset_delta = 44
locals = [ int ]
frame_type = 5 /* same */
frame_type = 4 /* same */
frame_type = 5 /* same */
frame_type = 5 /* same */
frame_type = 5 /* same */
frame_type = 2 /* same */
frame_type = 253 /* append */
offset_delta = 26
offset_delta = 25
locals = [ class "[I", int ]
frame_type = 10 /* same */
frame_type = 15 /* same */
Expand Down
Loading