2
2
#![ allow( unused) ]
3
3
#![ allow( non_snake_case) ]
4
4
5
- use super :: reljumps:: convert_to_absolute_jumps;
6
5
use super :: stack:: * ;
7
6
use super :: Instruction :: getfield;
8
7
use super :: * ;
@@ -121,7 +120,6 @@ fn make_default_constructor(class: &IRClass, constant_pool: &mut ConstantPool) -
121
120
}
122
121
code. push ( Instruction :: r#return) ;
123
122
124
- let code = convert_to_absolute_jumps ( code) ;
125
123
let stack_map_table = StackMapTable :: new ( & code, & [ ] , & constant_pool) ;
126
124
CompiledMethod {
127
125
name : "<init>" . to_string ( ) ,
@@ -456,40 +454,45 @@ pub struct NameAndType {
456
454
pub r#type : String ,
457
455
}
458
456
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
+
459
467
/// The instructions for the JVM
460
468
/// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.areturn
461
469
#[ derive( Debug , Copy , Clone , PartialEq ) ]
462
470
pub ( crate ) enum Instruction {
463
471
invokespecial( u16 ) , //Calling a method from the super class (probably only used in constructor)
464
472
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
476
483
ldc( u8 ) , //Push item from constant pool onto stack - For some reason only one byte for index into constant pool :shrug:
477
484
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
493
496
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
494
497
getfield( u16 ) , // Get field from object via an index into the constant pool
495
498
new( u16 ) , //Create new object
@@ -518,19 +521,19 @@ impl Instruction {
518
521
Instruction :: ldc( idx) => vec ! [ 18 , * idx] ,
519
522
Instruction :: ineg => vec ! [ 116 ] ,
520
523
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) ]
522
525
}
523
526
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) ]
525
528
}
526
529
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) ]
528
531
}
529
532
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) ]
531
534
}
532
535
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) ]
534
537
}
535
538
Instruction :: iadd => vec ! [ 96 ] ,
536
539
Instruction :: isub => vec ! [ 100 ] ,
@@ -541,9 +544,6 @@ impl Instruction {
541
544
Instruction :: getfield( idx) => vec ! [ 180 , high_byte( * idx) , low_byte( * idx) ] ,
542
545
Instruction :: new( idx) => vec ! [ 187 , high_byte( * idx) , low_byte( * idx) ] ,
543
546
Instruction :: dup => vec ! [ 89 ] ,
544
- // Instruction::relgoto() =>
545
- // Instruction::reljumpifeq(idx) =>
546
- // Instruction::reljumpifne(idx) =>
547
547
e => panic ! ( "Instruction {:?} not implemented or unexpected" , e) ,
548
548
}
549
549
}
@@ -615,7 +615,6 @@ fn generate_method(
615
615
{
616
616
code. push ( Instruction :: r#return) ;
617
617
}
618
- let code = convert_to_absolute_jumps ( code) ;
619
618
let stack_map_table = StackMapTable :: new ( & code, & method. params , & constant_pool) ;
620
619
CompiledMethod {
621
620
name : method. name . clone ( ) ,
@@ -733,9 +732,15 @@ fn generate_code_stmt(
733
732
// Generate bytecode for our body
734
733
let mut body =
735
734
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
+ ) ) ;
737
739
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
+ ) ) ;
739
744
}
740
745
Stmt :: LocalVarDecl ( types, name) => {
741
746
local_var_pool. add ( name. clone ( ) ) ;
@@ -771,10 +776,17 @@ fn generate_code_stmt(
771
776
local_var_pool,
772
777
class_name,
773
778
) ;
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
+ ) ) ;
775
783
}
776
784
// 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
+ ) ) ;
778
790
result. append ( & mut if_body) ;
779
791
// If there is an else block, append it
780
792
if stmt2. is_some ( ) {
@@ -1003,6 +1015,7 @@ fn generate_code_expr(
1003
1015
Expr :: TypedExpr ( expr, r#type) => match expr. deref ( ) {
1004
1016
Expr :: This => {
1005
1017
result. push ( Instruction :: aload ( 0 ) ) ;
1018
+ stack. inc ( 1 ) ;
1006
1019
}
1007
1020
Expr :: LocalVar ( name) => {
1008
1021
let idx = local_var_pool. get_index ( name) ;
@@ -1016,6 +1029,7 @@ fn generate_code_expr(
1016
1029
} ,
1017
1030
} ) ,
1018
1031
) ) ) ;
1032
+ stack. inc ( 3 ) ;
1019
1033
}
1020
1034
Expr :: FieldVar ( name) => {
1021
1035
let field_index = constant_pool. add ( Constant :: FieldRef ( FieldRef {
@@ -1027,6 +1041,7 @@ fn generate_code_expr(
1027
1041
} ) ) ;
1028
1042
result. push ( Instruction :: aload_0) ;
1029
1043
result. push ( Instruction :: getfield ( field_index) ) ;
1044
+ stack. inc ( 3 ) ;
1030
1045
}
1031
1046
_ => panic ! ( "Expected this got {:?}" , exprs) ,
1032
1047
} ,
@@ -1147,13 +1162,15 @@ fn generate_code_expr(
1147
1162
) ;
1148
1163
// If left operand is false (== 0), return false immediately
1149
1164
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
+ ) ) ;
1152
1169
// If right operand is false (== 0), return false
1153
1170
result. append ( & mut right_code) ;
1154
- result. push ( Instruction :: reljumpifeq ( 3 ) ) ;
1171
+ result. push ( Instruction :: ifeq ( 8 , 3 ) ) ;
1155
1172
result. push ( Instruction :: bipush ( 1 ) ) ;
1156
- result. push ( Instruction :: relgoto ( 2 ) ) ;
1173
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1157
1174
result. push ( Instruction :: bipush ( 0 ) ) ;
1158
1175
}
1159
1176
BinaryOp :: Or => {
@@ -1173,13 +1190,15 @@ fn generate_code_expr(
1173
1190
) ;
1174
1191
result. append ( & mut left_code) ;
1175
1192
// 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
+ ) ) ;
1178
1197
// If right operand is true (!= 0) return true
1179
1198
result. append ( & mut right_code) ;
1180
- result. push ( Instruction :: reljumpifne ( 3 ) ) ;
1199
+ result. push ( Instruction :: ifne ( 8 , 3 ) ) ;
1181
1200
result. push ( Instruction :: bipush ( 0 ) ) ;
1182
- result. push ( Instruction :: relgoto ( 2 ) ) ;
1201
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1183
1202
result. push ( Instruction :: bipush ( 1 ) ) ;
1184
1203
}
1185
1204
BinaryOp :: Le => {
@@ -1197,11 +1216,16 @@ fn generate_code_expr(
1197
1216
local_var_pool,
1198
1217
class_name,
1199
1218
) ) ;
1219
+ // a <= b
1220
+ // a - b <= 0
1221
+ // a - b - 1 < 0
1200
1222
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 ) ) ;
1204
1226
result. push ( Instruction :: bipush ( 0 ) ) ;
1227
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1228
+ result. push ( Instruction :: bipush ( 1 ) ) ;
1205
1229
}
1206
1230
BinaryOp :: Ge => {
1207
1231
result. append ( & mut generate_code_expr (
@@ -1219,10 +1243,10 @@ fn generate_code_expr(
1219
1243
class_name,
1220
1244
) ) ;
1221
1245
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 ) ) ;
1225
1247
result. push ( Instruction :: bipush ( 0 ) ) ;
1248
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1249
+ result. push ( Instruction :: bipush ( 1 ) ) ;
1226
1250
}
1227
1251
BinaryOp :: Lt => {
1228
1252
result. append ( & mut generate_code_expr (
@@ -1240,10 +1264,10 @@ fn generate_code_expr(
1240
1264
class_name,
1241
1265
) ) ;
1242
1266
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 ) ) ;
1246
1268
result. push ( Instruction :: bipush ( 0 ) ) ;
1269
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1270
+ result. push ( Instruction :: bipush ( 1 ) ) ;
1247
1271
}
1248
1272
BinaryOp :: Gt => {
1249
1273
result. append ( & mut generate_code_expr (
@@ -1260,11 +1284,16 @@ fn generate_code_expr(
1260
1284
local_var_pool,
1261
1285
class_name,
1262
1286
) ) ;
1287
+ // a >= b
1288
+ // a - b >= 0
1289
+ // a - b + 1 > 0
1263
1290
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 ) ) ;
1267
1294
result. push ( Instruction :: bipush ( 0 ) ) ;
1295
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1296
+ result. push ( Instruction :: bipush ( 1 ) ) ;
1268
1297
}
1269
1298
BinaryOp :: Eq => {
1270
1299
result. append ( & mut generate_code_expr (
@@ -1298,9 +1327,9 @@ fn generate_code_expr(
1298
1327
local_var_pool,
1299
1328
class_name,
1300
1329
) ) ;
1301
- result. push ( Instruction :: reljumpifeq ( 3 ) ) ;
1330
+ result. push ( Instruction :: ifeq ( 8 , 3 ) ) ;
1302
1331
result. push ( Instruction :: bipush ( 1 ) ) ;
1303
- result. push ( Instruction :: relgoto ( 2 ) ) ;
1332
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1304
1333
result. push ( Instruction :: bipush ( 0 ) )
1305
1334
}
1306
1335
}
@@ -1316,9 +1345,9 @@ fn generate_code_expr(
1316
1345
) ) ;
1317
1346
match UnaryOp :: from ( & op as & str ) {
1318
1347
UnaryOp :: Not => {
1319
- result. push ( Instruction :: reljumpifne ( 3 ) ) ;
1348
+ result. push ( Instruction :: ifne ( 8 , 3 ) ) ;
1320
1349
result. push ( Instruction :: bipush ( 1 ) ) ;
1321
- result. push ( Instruction :: relgoto ( 2 ) ) ;
1350
+ result. push ( Instruction :: goto ( 5 , 2 ) ) ;
1322
1351
result. push ( Instruction :: bipush ( 0 ) ) ;
1323
1352
}
1324
1353
UnaryOp :: Neg => {
0 commit comments