Skip to content

Commit bf6f204

Browse files
committed
fixed jumps and other stuff I guess
1 parent c0fb333 commit bf6f204

File tree

5 files changed

+107
-213
lines changed

5 files changed

+107
-213
lines changed

lib/src/codegen/ir.rs

+94-65
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#![allow(unused)]
33
#![allow(non_snake_case)]
44

5-
use super::reljumps::convert_to_absolute_jumps;
65
use super::stack::*;
76
use super::Instruction::getfield;
87
use super::*;
@@ -121,7 +120,6 @@ fn make_default_constructor(class: &IRClass, constant_pool: &mut ConstantPool) -
121120
}
122121
code.push(Instruction::r#return);
123122

124-
let code = convert_to_absolute_jumps(code);
125123
let stack_map_table = StackMapTable::new(&code, &[], &constant_pool);
126124
CompiledMethod {
127125
name: "<init>".to_string(),
@@ -456,40 +454,45 @@ pub struct NameAndType {
456454
pub r#type: String,
457455
}
458456

457+
fn get_instruction_length(istr: &Instruction) -> u16 {
458+
match istr {
459+
i => i.as_bytes().len() as u16,
460+
}
461+
}
462+
463+
fn get_instructions_length(instructions: &[Instruction]) -> u16 {
464+
instructions.iter().map(get_instruction_length).sum()
465+
}
466+
459467
/// The instructions for the JVM
460468
/// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.areturn
461469
#[derive(Debug, Copy, Clone, PartialEq)]
462470
pub(crate) enum Instruction {
463471
invokespecial(u16), //Calling a method from the super class (probably only used in constructor)
464472
aload_0,
465-
aload(u8), //Load reference from local variable
466-
iload(u8), //Load int from local variable
467-
ireturn, //return int, char, boolean
468-
r#return, //return void
469-
areturn, //return object(string, integer, null)
470-
bipush(i8), //Push signed byte onto stack
471-
sipush(i16), //Push signed short onto stack
472-
istore(u8), //Store int into local variable
473-
astore(u8), //Store reference into local variable
474-
reljumpifeq(i16), //relative jump, useful for if, while etc. Has i16 because it can jump backwards and it gets converted to u8 later
475-
aconst_null, //Push null onto stack
473+
aload(u8), //Load reference from local variable
474+
iload(u8), //Load int from local variable
475+
ireturn, //return int, char, boolean
476+
r#return, //return void
477+
areturn, //return object(string, integer, null)
478+
bipush(i8), //Push signed byte onto stack
479+
sipush(i16), //Push signed short onto stack
480+
istore(u8), //Store int into local variable
481+
astore(u8), //Store reference into local variable
482+
aconst_null, //Push null onto stack
476483
ldc(u8), //Push item from constant pool onto stack - For some reason only one byte for index into constant pool :shrug:
477484
ineg, //Negate int
478-
// @Note: All absolute jumps store first the adress in the list of bytes and then the relative jump in instructions
479-
ifeq(u16, i16), //Branch if int is 0
480-
iflt(u16, i16), //Branch if int is < 0
481-
ifge(u16, i16), //Branch if int is >= 0
482-
ifne(u16, i16), //Branch if int is not 0
483-
goto(u16, i16), //Jump to instruction
484-
relgoto(i16), //Jump to instruction relative to current instruction
485-
reljumpifne(i16), //relative jump, useful for if, while etc. Has i16 because it can jump backwards and it gets converted to u8 later
486-
reljumpiflt(i16), //relative jump, useful for if, while etc. Has i16 because it can jump backwards and it gets converted to u8 later
487-
reljumpifge(i16), //relative jump, useful for if, while etc. Has i16 because it can jump backwards and it gets converted to u8 later
488-
iadd, //Add int
489-
isub, //Subtract int
490-
imul, //Multiply int
491-
idiv, //Divide int
492-
irem, //Remainder int
485+
// @Note: All absolute jumps store first the relative offset in bytes and then in instructions
486+
ifeq(i16, i16), //Branch if int is 0
487+
iflt(i16, i16), //Branch if int is < 0
488+
ifge(i16, i16), //Branch if int is >= 0
489+
ifne(i16, i16), //Branch if int is not 0
490+
goto(i16, i16), //Jump to instruction
491+
iadd, //Add int
492+
isub, //Subtract int
493+
imul, //Multiply int
494+
idiv, //Divide int
495+
irem, //Remainder int
493496
putfield(u16), //Sets a value for the field at the given index. The stack must have the reference to the object to which the field belongs and on top of that the value to set the field to
494497
getfield(u16), // Get field from object via an index into the constant pool
495498
new(u16), //Create new object
@@ -518,19 +521,19 @@ impl Instruction {
518521
Instruction::ldc(idx) => vec![18, *idx],
519522
Instruction::ineg => vec![116],
520523
Instruction::ifeq(jmp_in_bytes, _jmp_in_inst) => {
521-
vec![153, high_byte(*jmp_in_bytes), low_byte(*jmp_in_bytes)]
524+
vec![153, shigh_byte(*jmp_in_bytes), slow_byte(*jmp_in_bytes)]
522525
}
523526
Instruction::ifne(jmp_in_bytes, _jmp_in_inst) => {
524-
vec![154, high_byte(*jmp_in_bytes), low_byte(*jmp_in_bytes)]
527+
vec![154, shigh_byte(*jmp_in_bytes), slow_byte(*jmp_in_bytes)]
525528
}
526529
Instruction::ifge(jmp_in_bytes, _jmp_in_inst) => {
527-
vec![156, high_byte(*jmp_in_bytes), low_byte(*jmp_in_bytes)]
530+
vec![156, shigh_byte(*jmp_in_bytes), slow_byte(*jmp_in_bytes)]
528531
}
529532
Instruction::iflt(jmp_in_bytes, _jmp_in_inst) => {
530-
vec![155, high_byte(*jmp_in_bytes), low_byte(*jmp_in_bytes)]
533+
vec![155, shigh_byte(*jmp_in_bytes), slow_byte(*jmp_in_bytes)]
531534
}
532535
Instruction::goto(jmp_in_bytes, _jmp_in_inst) => {
533-
vec![167, high_byte(*jmp_in_bytes), low_byte(*jmp_in_bytes)]
536+
vec![167, shigh_byte(*jmp_in_bytes), slow_byte(*jmp_in_bytes)]
534537
}
535538
Instruction::iadd => vec![96],
536539
Instruction::isub => vec![100],
@@ -541,9 +544,6 @@ impl Instruction {
541544
Instruction::getfield(idx) => vec![180, high_byte(*idx), low_byte(*idx)],
542545
Instruction::new(idx) => vec![187, high_byte(*idx), low_byte(*idx)],
543546
Instruction::dup => vec![89],
544-
// Instruction::relgoto() =>
545-
// Instruction::reljumpifeq(idx) =>
546-
// Instruction::reljumpifne(idx) =>
547547
e => panic!("Instruction {:?} not implemented or unexpected", e),
548548
}
549549
}
@@ -615,7 +615,6 @@ fn generate_method(
615615
{
616616
code.push(Instruction::r#return);
617617
}
618-
let code = convert_to_absolute_jumps(code);
619618
let stack_map_table = StackMapTable::new(&code, &method.params, &constant_pool);
620619
CompiledMethod {
621620
name: method.name.clone(),
@@ -733,9 +732,15 @@ fn generate_code_stmt(
733732
// Generate bytecode for our body
734733
let mut body =
735734
generate_code_stmt(*stmt, stack, constant_pool, local_var_pool, class_name);
736-
result.push(Instruction::reljumpifeq(body.len() as i16));
735+
result.push(Instruction::ifeq(
736+
2 + get_instructions_length(&body) as i16,
737+
body.len() as i16,
738+
));
737739
result.append(&mut body);
738-
result.push(Instruction::reljumpifeq(-(body.len() as i16)));
740+
result.push(Instruction::ifeq(
741+
-2 - (get_instructions_length(&body) as i16),
742+
-(body.len() as i16),
743+
));
739744
}
740745
Stmt::LocalVarDecl(types, name) => {
741746
local_var_pool.add(name.clone());
@@ -771,10 +776,17 @@ fn generate_code_stmt(
771776
local_var_pool,
772777
class_name,
773778
);
774-
if_body.push(Instruction::relgoto(else_body.len() as i16));
779+
if_body.push(Instruction::goto(
780+
2 + get_instructions_length(&else_body) as i16,
781+
else_body.len() as i16,
782+
));
775783
}
776784
// If the expression is false, jump to the else block
777-
result.push(Instruction::reljumpifne(if_body.len() as i16));
785+
dbg!(get_instructions_length(&if_body) as i16);
786+
result.push(Instruction::ifne(
787+
2 + get_instructions_length(&if_body) as i16,
788+
if_body.len() as i16,
789+
));
778790
result.append(&mut if_body);
779791
// If there is an else block, append it
780792
if stmt2.is_some() {
@@ -1003,6 +1015,7 @@ fn generate_code_expr(
10031015
Expr::TypedExpr(expr, r#type) => match expr.deref() {
10041016
Expr::This => {
10051017
result.push(Instruction::aload(0));
1018+
stack.inc(1);
10061019
}
10071020
Expr::LocalVar(name) => {
10081021
let idx = local_var_pool.get_index(name);
@@ -1016,6 +1029,7 @@ fn generate_code_expr(
10161029
},
10171030
}),
10181031
)));
1032+
stack.inc(3);
10191033
}
10201034
Expr::FieldVar(name) => {
10211035
let field_index = constant_pool.add(Constant::FieldRef(FieldRef {
@@ -1027,6 +1041,7 @@ fn generate_code_expr(
10271041
}));
10281042
result.push(Instruction::aload_0);
10291043
result.push(Instruction::getfield(field_index));
1044+
stack.inc(3);
10301045
}
10311046
_ => panic!("Expected this got {:?}", exprs),
10321047
},
@@ -1147,13 +1162,15 @@ fn generate_code_expr(
11471162
);
11481163
// If left operand is false (== 0), return false immediately
11491164
result.append(&mut left_code);
1150-
result.push(Instruction::reljumpifeq(2));
1151-
result.push(Instruction::relgoto(4 + right_code.len() as i16));
1165+
result.push(Instruction::ifeq(
1166+
11 + get_instructions_length(&right_code) as i16,
1167+
4 + right_code.len() as i16,
1168+
));
11521169
// If right operand is false (== 0), return false
11531170
result.append(&mut right_code);
1154-
result.push(Instruction::reljumpifeq(3));
1171+
result.push(Instruction::ifeq(8, 3));
11551172
result.push(Instruction::bipush(1));
1156-
result.push(Instruction::relgoto(2));
1173+
result.push(Instruction::goto(5, 2));
11571174
result.push(Instruction::bipush(0));
11581175
}
11591176
BinaryOp::Or => {
@@ -1173,13 +1190,15 @@ fn generate_code_expr(
11731190
);
11741191
result.append(&mut left_code);
11751192
// If left operand is true (!= 0), return true immediately
1176-
result.push(Instruction::reljumpifeq(2));
1177-
result.push(Instruction::relgoto(4 + right_code.len() as i16));
1193+
result.push(Instruction::ifne(
1194+
11 + get_instructions_length(&right_code) as i16,
1195+
4 + right_code.len() as i16,
1196+
));
11781197
// If right operand is true (!= 0) return true
11791198
result.append(&mut right_code);
1180-
result.push(Instruction::reljumpifne(3));
1199+
result.push(Instruction::ifne(8, 3));
11811200
result.push(Instruction::bipush(0));
1182-
result.push(Instruction::relgoto(2));
1201+
result.push(Instruction::goto(5, 2));
11831202
result.push(Instruction::bipush(1));
11841203
}
11851204
BinaryOp::Le => {
@@ -1197,11 +1216,16 @@ fn generate_code_expr(
11971216
local_var_pool,
11981217
class_name,
11991218
));
1219+
// a <= b
1220+
// a - b <= 0
1221+
// a - b - 1 < 0
12001222
result.push(Instruction::isub);
1201-
result.push(Instruction::reljumpiflt(3));
1202-
result.push(Instruction::bipush(1));
1203-
result.push(Instruction::relgoto(2));
1223+
result.push(Instruction::iload(1));
1224+
result.push(Instruction::isub);
1225+
result.push(Instruction::iflt(8, 3));
12041226
result.push(Instruction::bipush(0));
1227+
result.push(Instruction::goto(5, 2));
1228+
result.push(Instruction::bipush(1));
12051229
}
12061230
BinaryOp::Ge => {
12071231
result.append(&mut generate_code_expr(
@@ -1219,10 +1243,10 @@ fn generate_code_expr(
12191243
class_name,
12201244
));
12211245
result.push(Instruction::isub);
1222-
result.push(Instruction::reljumpifge(3));
1223-
result.push(Instruction::bipush(1));
1224-
result.push(Instruction::relgoto(2));
1246+
result.push(Instruction::ifge(8, 3));
12251247
result.push(Instruction::bipush(0));
1248+
result.push(Instruction::goto(5, 2));
1249+
result.push(Instruction::bipush(1));
12261250
}
12271251
BinaryOp::Lt => {
12281252
result.append(&mut generate_code_expr(
@@ -1240,10 +1264,10 @@ fn generate_code_expr(
12401264
class_name,
12411265
));
12421266
result.push(Instruction::isub);
1243-
result.push(Instruction::reljumpifge(3));
1244-
result.push(Instruction::bipush(1));
1245-
result.push(Instruction::relgoto(2));
1267+
result.push(Instruction::iflt(8, 3));
12461268
result.push(Instruction::bipush(0));
1269+
result.push(Instruction::goto(5, 2));
1270+
result.push(Instruction::bipush(1));
12471271
}
12481272
BinaryOp::Gt => {
12491273
result.append(&mut generate_code_expr(
@@ -1260,11 +1284,16 @@ fn generate_code_expr(
12601284
local_var_pool,
12611285
class_name,
12621286
));
1287+
// a >= b
1288+
// a - b >= 0
1289+
// a - b + 1 > 0
12631290
result.push(Instruction::isub);
1264-
result.push(Instruction::reljumpiflt(3));
1265-
result.push(Instruction::bipush(1));
1266-
result.push(Instruction::relgoto(2));
1291+
result.push(Instruction::iload(1));
1292+
result.push(Instruction::iadd);
1293+
result.push(Instruction::ifge(8, 3));
12671294
result.push(Instruction::bipush(0));
1295+
result.push(Instruction::goto(5, 2));
1296+
result.push(Instruction::bipush(1));
12681297
}
12691298
BinaryOp::Eq => {
12701299
result.append(&mut generate_code_expr(
@@ -1298,9 +1327,9 @@ fn generate_code_expr(
12981327
local_var_pool,
12991328
class_name,
13001329
));
1301-
result.push(Instruction::reljumpifeq(3));
1330+
result.push(Instruction::ifeq(8, 3));
13021331
result.push(Instruction::bipush(1));
1303-
result.push(Instruction::relgoto(2));
1332+
result.push(Instruction::goto(5, 2));
13041333
result.push(Instruction::bipush(0))
13051334
}
13061335
}
@@ -1316,9 +1345,9 @@ fn generate_code_expr(
13161345
));
13171346
match UnaryOp::from(&op as &str) {
13181347
UnaryOp::Not => {
1319-
result.push(Instruction::reljumpifne(3));
1348+
result.push(Instruction::ifne(8, 3));
13201349
result.push(Instruction::bipush(1));
1321-
result.push(Instruction::relgoto(2));
1350+
result.push(Instruction::goto(5, 2));
13221351
result.push(Instruction::bipush(0));
13231352
}
13241353
UnaryOp::Neg => {

lib/src/codegen/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
mod bytecode;
22
pub mod ir;
3-
mod reljumps;
43
mod stack;
54
pub use ir::*;
65

@@ -11,3 +10,11 @@ pub fn high_byte(short: u16) -> u8 {
1110
pub fn low_byte(short: u16) -> u8 {
1211
short as u8
1312
}
13+
14+
pub fn shigh_byte(short: i16) -> u8 {
15+
(short >> 8) as u8
16+
}
17+
18+
pub fn slow_byte(short: i16) -> u8 {
19+
short as u8
20+
}

0 commit comments

Comments
 (0)