Compare commits
2 commits
6610b09c16
...
b053461e74
Author | SHA1 | Date | |
---|---|---|---|
b053461e74 | |||
c6e4ecec3d |
6 changed files with 708 additions and 197 deletions
242
src/bytecode.rs
242
src/bytecode.rs
|
@ -25,12 +25,16 @@ impl Bytecode {
|
||||||
0x0E => (Instruction::PushConstDouble0(), 1),
|
0x0E => (Instruction::PushConstDouble0(), 1),
|
||||||
0x0F => (Instruction::PushConstDouble1(), 1),
|
0x0F => (Instruction::PushConstDouble1(), 1),
|
||||||
|
|
||||||
0x10 => (Instruction::LoadByteImmediate(self.bytes[offset+1]), 2),
|
0x10 => (Instruction::LoadByteImmediate(i8::from_be_bytes([self.bytes[offset+1]])), 2),
|
||||||
0x11 => (Instruction::LoadShortImmediate((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0x11 => {
|
||||||
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||||
|
(Instruction::LoadShortImmediate(i16::from_be_bytes(bytes)), 3)
|
||||||
|
}
|
||||||
0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2),
|
0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2),
|
||||||
0x13 => (Instruction::LoadCostantWide((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0x13 => (Instruction::LoadCostantWide((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
|
|
||||||
|
0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2),
|
||||||
0x1A => (Instruction::LoadLocalInt0(), 1),
|
0x1A => (Instruction::LoadLocalInt0(), 1),
|
||||||
0x1B => (Instruction::LoadLocalInt1(), 1),
|
0x1B => (Instruction::LoadLocalInt1(), 1),
|
||||||
0x1C => (Instruction::LoadLocalInt2(), 1),
|
0x1C => (Instruction::LoadLocalInt2(), 1),
|
||||||
|
@ -49,30 +53,36 @@ impl Bytecode {
|
||||||
0x2D => (Instruction::LoadLocalReference3(), 1),
|
0x2D => (Instruction::LoadLocalReference3(), 1),
|
||||||
|
|
||||||
0x32 => (Instruction::ArrayElement(), 1),
|
0x32 => (Instruction::ArrayElement(), 1),
|
||||||
|
0x33 => (Instruction::LoadFromBArray(), 1),
|
||||||
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
|
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
|
||||||
|
0x3A => (Instruction::StoreLocalReference(self.bytes[offset+1]), 2),
|
||||||
0x3B => (Instruction::StoreLocalInt0(), 1),
|
0x3B => (Instruction::StoreLocalInt0(), 1),
|
||||||
0x3C => (Instruction::StoreLocalInt1(), 1),
|
0x3C => (Instruction::StoreLocalInt1(), 1),
|
||||||
0x3D => (Instruction::StoreLocalInt2(), 1),
|
0x3D => (Instruction::StoreLocalInt2(), 1),
|
||||||
0x3E => (Instruction::StoreLocalInt3(), 1),
|
0x3E => (Instruction::StoreLocalInt3(), 1),
|
||||||
0x4B => (Instruction::StoreReference0(), 1),
|
0x4B => (Instruction::StoreLocalReference0(), 1),
|
||||||
0x4C => (Instruction::StoreReference1(), 1),
|
0x4C => (Instruction::StoreLocalReference1(), 1),
|
||||||
0x4D => (Instruction::StoreReference2(), 1),
|
0x4D => (Instruction::StoreLocalReference2(), 1),
|
||||||
0x4E => (Instruction::StoreReference3(), 1),
|
0x4E => (Instruction::StoreLocalReference3(), 1),
|
||||||
|
|
||||||
0x53 => (Instruction::StoreIntoRArray(), 1),
|
0x53 => (Instruction::StoreIntoRArray(), 1),
|
||||||
0x54 => (Instruction::StoreIntoBArray(), 1),
|
0x54 => (Instruction::StoreIntoBArray(), 1),
|
||||||
|
0x55 => (Instruction::StoreIntoCArray(), 1),
|
||||||
|
|
||||||
0x57 => (Instruction::Pop(), 1),
|
0x57 => (Instruction::Pop(), 1),
|
||||||
0x59 => (Instruction::Duplicate(), 1),
|
0x59 => (Instruction::Duplicate(), 1),
|
||||||
|
|
||||||
0x60 => (Instruction::AddInt(), 1),
|
0x60 => (Instruction::AddInt(), 1),
|
||||||
|
0x64 => (Instruction::SubtractInt(), 1),
|
||||||
0x68 => (Instruction::MultiplyInt(), 1),
|
0x68 => (Instruction::MultiplyInt(), 1),
|
||||||
0x6C => (Instruction::DivideInt(), 1),
|
0x6C => (Instruction::DivideInt(), 1),
|
||||||
0x6D => (Instruction::DivideLong(), 1),
|
0x6D => (Instruction::DivideLong(), 1),
|
||||||
|
|
||||||
0x7A => (Instruction::ShiftIntRight(), 1),
|
0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
|
||||||
|
0x7C => (Instruction::LogicalShiftIntRight(), 1),
|
||||||
|
|
||||||
0x80 => (Instruction::OrInt(), 1),
|
0x80 => (Instruction::OrInt(), 1),
|
||||||
|
0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3),
|
||||||
|
|
||||||
0x95 => (Instruction::CompareFloatL(), 1),
|
0x95 => (Instruction::CompareFloatL(), 1),
|
||||||
0x96 => (Instruction::CompareFloatG(), 1),
|
0x96 => (Instruction::CompareFloatG(), 1),
|
||||||
|
@ -133,13 +143,31 @@ impl Bytecode {
|
||||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||||
(Instruction::BranchReferenceInequality(i16::from_be_bytes(bytes)), 3)
|
(Instruction::BranchReferenceInequality(i16::from_be_bytes(bytes)), 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
0xAC => (Instruction::ReturnInt(), 1),
|
|
||||||
0xA7 => {
|
0xA7 => {
|
||||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||||
(Instruction::BranchAlways(i16::from_be_bytes(bytes)), 3)
|
(Instruction::BranchAlways(i16::from_be_bytes(bytes)), 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0xAB => {
|
||||||
|
let padding = 4 - (offset % 4) - 1;
|
||||||
|
let default_bytes = [self.bytes[offset+padding+1], self.bytes[offset+padding+2], self.bytes[offset+padding+3], self.bytes[offset+padding+4]];
|
||||||
|
let default = i32::from_be_bytes(default_bytes);
|
||||||
|
|
||||||
|
let npairs_bytes = [self.bytes[offset+padding+5], self.bytes[offset+padding+6], self.bytes[offset+padding+7], self.bytes[offset+padding+8]];
|
||||||
|
let npairs = i32::from_be_bytes(npairs_bytes);
|
||||||
|
|
||||||
|
let mut pairs_vec = Vec::with_capacity(npairs as usize);
|
||||||
|
for i in 0..npairs as usize {
|
||||||
|
let match_bytes = [self.bytes[offset+padding+8*(1+i)+1], self.bytes[offset+padding+8*(1+i)+2], self.bytes[offset+padding+8*(1+i)+3], self.bytes[offset+padding+8*(1+i)+4]];
|
||||||
|
let offset_bytes = [self.bytes[offset+padding+8*(1+i)+5], self.bytes[offset+padding+8*(1+i)+6], self.bytes[offset+padding+8*(1+i)+7], self.bytes[offset+padding+8*(1+i)+8]];
|
||||||
|
|
||||||
|
pairs_vec.push((i32::from_be_bytes(match_bytes), i32::from_be_bytes(offset_bytes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
(Instruction::LookupSwitch(default, pairs_vec.into()), 1 + padding + 4 + 4 + npairs as usize * 8)
|
||||||
|
}
|
||||||
|
0xAC => (Instruction::ReturnInt(), 1),
|
||||||
|
|
||||||
0xB0 => (Instruction::ReturnReference(), 1),
|
0xB0 => (Instruction::ReturnReference(), 1),
|
||||||
0xB1 => (Instruction::ReturnVoid(), 1),
|
0xB1 => (Instruction::ReturnVoid(), 1),
|
||||||
0xB2 => (Instruction::GetStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0xB2 => (Instruction::GetStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
|
@ -155,6 +183,7 @@ impl Bytecode {
|
||||||
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
0xBE => (Instruction::ArrayLength(), 1),
|
0xBE => (Instruction::ArrayLength(), 1),
|
||||||
|
|
||||||
|
0xC0 => (Instruction::CheckCast((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
0xC1 => (Instruction::InstanceOf((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0xC1 => (Instruction::InstanceOf((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
0xC2 => (Instruction::EnterMonitor(), 1),
|
0xC2 => (Instruction::EnterMonitor(), 1),
|
||||||
0xC3 => (Instruction::ExitMonitor(), 1),
|
0xC3 => (Instruction::ExitMonitor(), 1),
|
||||||
|
@ -198,111 +227,120 @@ impl Debug for Bytecode {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
NoOperation() = 0x00, // No-Operation
|
NoOperation() = 0x00, // No-Operation
|
||||||
PushNull() = 0x01, // ..., arrayref, index, value
|
PushNull() = 0x01, // ..., arrayref, index, value
|
||||||
PushConstIntM1() = 0x02, // Push -1
|
PushConstIntM1() = 0x02, // Push -1
|
||||||
PushConstInt0() = 0x03, // Push 0
|
PushConstInt0() = 0x03, // Push 0
|
||||||
PushConstInt1() = 0x04, // Push 1
|
PushConstInt1() = 0x04, // Push 1
|
||||||
PushConstInt2() = 0x05, // Push 2
|
PushConstInt2() = 0x05, // Push 2
|
||||||
PushConstInt3() = 0x06, // Push 3
|
PushConstInt3() = 0x06, // Push 3
|
||||||
PushConstInt4() = 0x07, // Push 4
|
PushConstInt4() = 0x07, // Push 4
|
||||||
PushConstInt5() = 0x08, // Push 5
|
PushConstInt5() = 0x08, // Push 5
|
||||||
PushConstFloat0() = 0x0B, // Push 0.0f
|
PushConstFloat0() = 0x0B, // Push 0.0f
|
||||||
PushConstFloat1() = 0x0C, // Push 1.0f
|
PushConstFloat1() = 0x0C, // Push 1.0f
|
||||||
PushConstFloat2() = 0x0D, // Push 2.0f
|
PushConstFloat2() = 0x0D, // Push 2.0f
|
||||||
PushConstDouble0() = 0x0E, // Push 0.0
|
PushConstDouble0() = 0x0E, // Push 0.0
|
||||||
PushConstDouble1() = 0x0F, // Push 1.0
|
PushConstDouble1() = 0x0F, // Push 1.0
|
||||||
|
|
||||||
LoadByteImmediate(u8) = 0x10, // push immediate short
|
LoadByteImmediate(i8) = 0x10, // push immediate short
|
||||||
LoadShortImmediate(u16) = 0x11, // push immediate short
|
LoadShortImmediate(i16) = 0x11, // push immediate short
|
||||||
LoadConstant(u8) = 0x12, // Push from constant pool
|
LoadConstant(u8) = 0x12, // Push from constant pool
|
||||||
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
|
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
|
||||||
// double or long or whatever
|
// double or long or whatever
|
||||||
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
||||||
LoadLocalInt0() = 0x1A, // Load int from local variable
|
LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable
|
||||||
LoadLocalInt1() = 0x1B, // Load int from local variable
|
LoadLocalInt0() = 0x1A, // Load int from local variable
|
||||||
LoadLocalInt2() = 0x1C, // Load int from local variable
|
LoadLocalInt1() = 0x1B, // Load int from local variable
|
||||||
LoadLocalInt3() = 0x1D, // Load int from local variable
|
LoadLocalInt2() = 0x1C, // Load int from local variable
|
||||||
|
LoadLocalInt3() = 0x1D, // Load int from local variable
|
||||||
|
|
||||||
LoadLocalFloat0() = 0x22, // Load local double variable reference onto stack
|
LoadLocalFloat0() = 0x22, // Load local double variable reference onto stack
|
||||||
LoadLocalFloat1() = 0x23, // Load local double variable reference onto stack
|
LoadLocalFloat1() = 0x23, // Load local double variable reference onto stack
|
||||||
LoadLocalFloat2() = 0x24, // Load local double variable reference onto stack
|
LoadLocalFloat2() = 0x24, // Load local double variable reference onto stack
|
||||||
LoadLocalFloat3() = 0x25, // Load local double variable reference onto stack
|
LoadLocalFloat3() = 0x25, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
|
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
|
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
|
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack
|
LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack
|
||||||
LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack
|
LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack
|
||||||
LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack
|
LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack
|
||||||
LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack
|
LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack
|
||||||
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
|
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
|
||||||
|
|
||||||
ArrayElement() = 0x32, // load element from array
|
ArrayElement() = 0x32, // load element from array
|
||||||
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
LoadFromBArray() = 0x33, // store into byte array
|
||||||
StoreLocalInt0() = 0x3B, // store int into local variable
|
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
||||||
StoreLocalInt1() = 0x3C, // store int into local variable
|
StoreLocalReference(u8) = 0x3A, // store into indexed local variable
|
||||||
StoreLocalInt2() = 0x3D, // store int into local variable
|
StoreLocalInt0() = 0x3B, // store int into local variable
|
||||||
StoreLocalInt3() = 0x3E, // store int into local variable
|
StoreLocalInt1() = 0x3C, // store int into local variable
|
||||||
StoreReference0() = 0x4B, // store reference into local variable
|
StoreLocalInt2() = 0x3D, // store int into local variable
|
||||||
StoreReference1() = 0x4C, // store reference into local variable
|
StoreLocalInt3() = 0x3E, // store int into local variable
|
||||||
StoreReference2() = 0x4D, // store reference into local variable
|
StoreLocalReference0() = 0x4B, // store reference into local variable
|
||||||
StoreReference3() = 0x4E, // store reference into local variable
|
StoreLocalReference1() = 0x4C, // store reference into local variable
|
||||||
|
StoreLocalReference2() = 0x4D, // store reference into local variable
|
||||||
|
StoreLocalReference3() = 0x4E, // store reference into local variable
|
||||||
|
|
||||||
StoreIntoRArray() = 0x53, // store value into reference array
|
StoreIntoRArray() = 0x53, // store value into reference array
|
||||||
StoreIntoBArray() = 0x54, // store value into byte or boolean array
|
StoreIntoBArray() = 0x54, // store value into byte or boolean array
|
||||||
Pop() = 0x57, // Pop top stack value
|
StoreIntoCArray() = 0x55, // store value into char array
|
||||||
Duplicate() = 0x59, // duplicate top stack value
|
Pop() = 0x57, // Pop top stack value
|
||||||
|
Duplicate() = 0x59, // duplicate top stack value
|
||||||
|
|
||||||
AddInt() = 0x60, // int addition
|
AddInt() = 0x60, // int addition
|
||||||
MultiplyInt() = 0x68, // int multiplication
|
SubtractInt() = 0x64, // int subtraction
|
||||||
DivideInt() = 0x6C, // integer division, round toward zero and more rules
|
MultiplyInt() = 0x68, // int multiplication
|
||||||
DivideLong() = 0x6D, // long division
|
DivideInt() = 0x6C, // integer division, round toward zero and more rules
|
||||||
|
DivideLong() = 0x6D, // long division
|
||||||
|
|
||||||
ShiftIntRight() = 0x7a, // shift int
|
ArithmeticShiftIntRight() = 0x7A, // shift int
|
||||||
|
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
|
||||||
|
|
||||||
OrInt() = 0x80, // value, value => or
|
OrInt() = 0x80, // value, value => or
|
||||||
|
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
|
||||||
|
|
||||||
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
||||||
CompareFloatG() = 0x96, // compare float, push 1 if one is NaN
|
CompareFloatG() = 0x96, // compare float, push 1 if one is NaN
|
||||||
BranchZero(i16) = 0x99, // branch if value == 0
|
BranchZero(i16) = 0x99, // branch if value == 0
|
||||||
BranchNonZero(i16) = 0x9A, // branch if value != 0
|
BranchNonZero(i16) = 0x9A, // branch if value != 0
|
||||||
BranchNegative(i16) = 0x9B, // branch if value < 0
|
BranchNegative(i16) = 0x9B, // branch if value < 0
|
||||||
BranchNonNegative(i16) = 0x9C, // branch if value <= 0
|
BranchNonNegative(i16) = 0x9C, // branch if value <= 0
|
||||||
BranchPositive(i16) = 0x9D, // branch if value > 0
|
BranchPositive(i16) = 0x9D, // branch if value > 0
|
||||||
BranchNonPositive(i16) = 0x9E, // branch if value >= 0
|
BranchNonPositive(i16) = 0x9E, // branch if value >= 0
|
||||||
|
|
||||||
BranchIntEquality(i16) = 0x9F,
|
BranchIntEquality(i16) = 0x9F,
|
||||||
BranchIntInequality(i16) = 0xA0,
|
BranchIntInequality(i16) = 0xA0,
|
||||||
BranchIntLessThan(i16) = 0xA1,
|
BranchIntLessThan(i16) = 0xA1,
|
||||||
BranchIntGreaterEquals(i16) = 0xA2,
|
BranchIntGreaterEquals(i16) = 0xA2,
|
||||||
BranchIntGreaterThan(i16) = 0xA3,
|
BranchIntGreaterThan(i16) = 0xA3,
|
||||||
BranchIntLessEquals(i16) = 0xA4,
|
BranchIntLessEquals(i16) = 0xA4,
|
||||||
BranchReferenceEquality(i16) = 0xA5,
|
BranchReferenceEquality(i16) = 0xA5,
|
||||||
BranchReferenceInequality(i16) = 0xA6,
|
BranchReferenceInequality(i16) = 0xA6,
|
||||||
|
|
||||||
BranchAlways(i16) = 0xA7, // branch if true
|
BranchAlways(i16) = 0xA7, // branch if true
|
||||||
ReturnInt() = 0xAC, // return integer from function
|
LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // offset based on switch value
|
||||||
|
ReturnInt() = 0xAC, // return integer from function
|
||||||
|
|
||||||
ReturnReference() = 0xB0, // return top-ref from current function
|
ReturnReference() = 0xB0, // return top-ref from current function
|
||||||
ReturnVoid() = 0xB1, // return void from function
|
ReturnVoid() = 0xB1, // return void from function
|
||||||
GetStatic(u16) = 0xB2, // get static field from class
|
GetStatic(u16) = 0xB2, // get static field from class
|
||||||
PutStatic(u16) = 0xB3, // set static field on class
|
PutStatic(u16) = 0xB3, // set static field on class
|
||||||
GetField(u16) = 0xB4, // get field from class
|
GetField(u16) = 0xB4, // get field from class
|
||||||
PutField(u16) = 0xB5, // set field to a value
|
PutField(u16) = 0xB5, // set field to a value
|
||||||
InvokeVirtual(u16) = 0xB6, // invoke function on a class
|
InvokeVirtual(u16) = 0xB6, // invoke function on a class
|
||||||
InvokeSpecial(u16) = 0xB7, // invoke instance method
|
InvokeSpecial(u16) = 0xB7, // invoke instance method
|
||||||
InvokeStatic(u16) = 0xB8, // invoke static function
|
InvokeStatic(u16) = 0xB8, // invoke static function
|
||||||
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
||||||
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
|
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
|
||||||
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
|
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
|
||||||
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
||||||
ArrayLength() = 0xBE, // Get length from array reference
|
ArrayLength() = 0xBE, // Get length from array reference
|
||||||
|
|
||||||
InstanceOf(u16) = 0xC1, // branch if Null
|
CheckCast(u16) = 0xC0, // throw exception on fail
|
||||||
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
|
InstanceOf(u16) = 0xC1, // push integer result for success
|
||||||
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
|
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
|
||||||
BranchNull(i16) = 0xC6, // branch if Null
|
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
|
||||||
BranchNonNull(i16) = 0xC7, // branch if Null
|
BranchNull(i16) = 0xC6, // branch if Null
|
||||||
|
BranchNonNull(i16) = 0xC7, // branch if Null
|
||||||
|
|
||||||
Unknown(u8),
|
Unknown(u8),
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub struct PrimitiveClassStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ClassStoreEntry {
|
pub struct ClassStoreEntry {
|
||||||
was_init: bool,
|
was_init: bool,
|
||||||
class_object: ObjectReference,
|
class_object: ObjectReference,
|
||||||
class_file: JavaClassFile,
|
class_file: JavaClassFile,
|
||||||
|
@ -133,6 +133,8 @@ impl ClassStore {
|
||||||
if path_buf.is_file() {
|
if path_buf.is_file() {
|
||||||
return self.load_class_from_file(&path_buf);
|
return self.load_class_from_file(&path_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path_buf.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath")));
|
return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath")));
|
||||||
|
@ -154,10 +156,12 @@ impl ClassStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
let compatible_count = CompatibleTypesIterator::new(my_type_index, self)
|
let compatible_count = CompatibleTypesIterator::new(my_type_index, self)
|
||||||
.filter(|type_name| *type_name == other_type_name)
|
.filter(|type_name|
|
||||||
|
*type_name == other_type_name
|
||||||
|
)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
compatible_count == 0
|
compatible_count != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn have_class(&self, classname: &String) -> bool {
|
pub fn have_class(&self, classname: &String) -> bool {
|
||||||
|
|
105
src/heap_area.rs
105
src/heap_area.rs
|
@ -76,27 +76,40 @@ impl HeapArea {
|
||||||
byte_buffer
|
byte_buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
let byte_object_refs = utf16_bytes.iter().map(|byte| self.object_area.cached_byte_object(*byte)).collect();
|
let byte_array_ref = self.make_primitive_byte_array(utf16_bytes.len(), class_store);
|
||||||
|
|
||||||
let byte_array_ref = self.make_array(class_store, byte_object_refs);
|
|
||||||
|
|
||||||
|
for (index, byte) in utf16_bytes.iter().enumerate() {
|
||||||
|
self.object_area.set_array_element(byte_array_ref, index, FieldValue::Byte(i8::from_ne_bytes([*byte])));
|
||||||
|
}
|
||||||
|
|
||||||
let string_class_index = class_store.class_idx_from_name(&String::from("java/lang/String")).unwrap();
|
let string_class_index = class_store.class_idx_from_name(&String::from("java/lang/String")).unwrap();
|
||||||
let string_ref = self.make_object(class_store, string_class_index);
|
let string_ref = self.make_object(class_store, string_class_index);
|
||||||
|
|
||||||
self.object_area.set_object_field(string_ref, "value", FieldValue::Reference(byte_array_ref), string_class_index, class_store).unwrap();
|
self.object_area.set_object_field(string_ref, "value", FieldValue::Reference(byte_array_ref), string_class_index, class_store).unwrap();
|
||||||
const UTF16_CODER: u8 = 1; // TODO: I don't like this
|
const UTF16_CODER: i8 = 1; // TODO: I don't like this
|
||||||
self.object_area.set_object_field(string_ref, "coder", FieldValue::Byte(UTF16_CODER), string_class_index, class_store).unwrap();
|
self.object_area.set_object_field(string_ref, "coder", FieldValue::Byte(UTF16_CODER), string_class_index, class_store).unwrap();
|
||||||
|
|
||||||
string_ref
|
string_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_primitive_char_array(&mut self, array_capacity: usize, class_store: &ClassStore) -> ObjectReference {
|
||||||
|
let (array_ref, size) = self.object_area.make_primitive_char_array(array_capacity, class_store);
|
||||||
|
self.memory_used += size;
|
||||||
|
|
||||||
|
array_ref
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
pub struct ObjectReference(u32);
|
pub struct ObjectReference(u32);
|
||||||
|
|
||||||
|
|
||||||
|
impl Into<FieldValue> for ObjectReference {
|
||||||
|
fn into(self) -> FieldValue {
|
||||||
|
FieldValue::Reference(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ObjectReference {
|
impl ObjectReference {
|
||||||
pub const NULL: ObjectReference = ObjectReference(0);
|
pub const NULL: ObjectReference = ObjectReference(0);
|
||||||
}
|
}
|
||||||
|
@ -118,7 +131,7 @@ impl ObjectArea {
|
||||||
fn fill_byte_cache(&mut self, class_store: &ClassStore) -> usize {
|
fn fill_byte_cache(&mut self, class_store: &ClassStore) -> usize {
|
||||||
let byte_class_index = class_store.class_idx_from_name(&String::from("java/lang/Byte")).unwrap();
|
let byte_class_index = class_store.class_idx_from_name(&String::from("java/lang/Byte")).unwrap();
|
||||||
let mut total_memory_usage = 0;
|
let mut total_memory_usage = 0;
|
||||||
for byte in 0..=u8::MAX {
|
for byte in i8::MIN..=i8::MAX {
|
||||||
let (byte_object_ref, object_memory) = self.make(class_store, byte_class_index);
|
let (byte_object_ref, object_memory) = self.make(class_store, byte_class_index);
|
||||||
self.set_object_field(byte_object_ref, "value", FieldValue::Byte(byte), byte_class_index, class_store).unwrap();
|
self.set_object_field(byte_object_ref, "value", FieldValue::Byte(byte), byte_class_index, class_store).unwrap();
|
||||||
|
|
||||||
|
@ -147,7 +160,7 @@ impl ObjectArea {
|
||||||
|
|
||||||
let array_object = ByteArray {
|
let array_object = ByteArray {
|
||||||
class_ref: array_class_ref,
|
class_ref: array_class_ref,
|
||||||
content: vec![0_u8; capacity].into(),
|
content: vec![0_i8; capacity].into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let array_ref = self.store_entry(CompartmentEntry::ByteArray(array_object));
|
let array_ref = self.store_entry(CompartmentEntry::ByteArray(array_object));
|
||||||
|
@ -214,8 +227,7 @@ impl ObjectArea {
|
||||||
return (object_ref, object_size);
|
return (object_ref, object_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
pub fn get_class_ref_native_class_name<'a>(&self, class_ref: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
||||||
let class_ref = self.get_reference_class_ref(reference, class_store);
|
|
||||||
let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() {
|
let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() {
|
||||||
FieldValue::Reference(r) => r,
|
FieldValue::Reference(r) => r,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -228,6 +240,11 @@ impl ObjectArea {
|
||||||
return class_store.get_native_class_name(native_name_index as usize);
|
return class_store.get_native_class_name(native_name_index as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
||||||
|
let class_ref = self.get_reference_class_ref(reference, class_store);
|
||||||
|
self.get_class_ref_native_class_name(class_ref, class_store)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_object_class_index(&self, reference: ObjectReference) -> usize {
|
pub fn get_object_class_index(&self, reference: ObjectReference) -> usize {
|
||||||
match self.get_entry(reference) {
|
match self.get_entry(reference) {
|
||||||
CompartmentEntry::Object(o) => o.class_index,
|
CompartmentEntry::Object(o) => o.class_index,
|
||||||
|
@ -282,22 +299,26 @@ impl ObjectArea {
|
||||||
|
|
||||||
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
||||||
// TODO: Throw errors
|
// TODO: Throw errors
|
||||||
let array = match self.get_entry(reference) {
|
match self.get_entry(reference) {
|
||||||
CompartmentEntry::ReferenceArray(a) => a,
|
CompartmentEntry::ReferenceArray(a) => a.content.len(),
|
||||||
|
CompartmentEntry::ByteArray(b) => b.content.len(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
}
|
||||||
|
|
||||||
array.content.len()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> ObjectReference {
|
pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> FieldValue {
|
||||||
// TODO: Throw errors
|
// TODO: Throw errors
|
||||||
let array = match self.get_entry(array_ref) {
|
match self.get_entry(array_ref) {
|
||||||
CompartmentEntry::ReferenceArray(a) => a,
|
CompartmentEntry::ReferenceArray(array) => {
|
||||||
|
let element = array.content[element_index as usize];
|
||||||
|
FieldValue::Reference(element)
|
||||||
|
}
|
||||||
|
CompartmentEntry::ByteArray(array) => {
|
||||||
|
let element = array.content[element_index as usize];
|
||||||
|
FieldValue::Byte(element)
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
}
|
||||||
|
|
||||||
array.content[element_index as usize]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_object_field(&self, reference: ObjectReference, field_name: &str, accessing_class_idx: usize, class_store: &ClassStore) -> Result<FieldValue, Error> {
|
pub fn get_object_field(&self, reference: ObjectReference, field_name: &str, accessing_class_idx: usize, class_store: &ClassStore) -> Result<FieldValue, Error> {
|
||||||
|
@ -335,12 +356,17 @@ impl ObjectArea {
|
||||||
let array_element = array.content.get_mut(index).unwrap();
|
let array_element = array.content.get_mut(index).unwrap();
|
||||||
|
|
||||||
*array_element = match element { FieldValue::Reference(r) => r, _ => unreachable!() } ;
|
*array_element = match element { FieldValue::Reference(r) => r, _ => unreachable!() } ;
|
||||||
},
|
}
|
||||||
CompartmentEntry::ByteArray(array) => {
|
CompartmentEntry::ByteArray(array) => {
|
||||||
let array_element = array.content.get_mut(index).unwrap();
|
let array_element = array.content.get_mut(index).unwrap();
|
||||||
|
|
||||||
*array_element = match element { FieldValue::Byte(b) => b, _ => unreachable!() } ;
|
*array_element = match element { FieldValue::Byte(b) => b, _ => unreachable!() } ;
|
||||||
},
|
}
|
||||||
|
CompartmentEntry::CharArray(array) => {
|
||||||
|
let array_element = array.content.get_mut(index).unwrap();
|
||||||
|
|
||||||
|
*array_element = match element { FieldValue::Char(c) => c, _ => unreachable!() } ;
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -387,6 +413,27 @@ impl ObjectArea {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_primitive_char_array(&mut self, array_capacity: usize, class_store: &ClassStore) -> (ObjectReference, usize) {
|
||||||
|
// make new type desc
|
||||||
|
let array_type_desc = AbstractTypeDescription {
|
||||||
|
array_level: 1,
|
||||||
|
kind: AbstractTypeKind::Char(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let array_class_ref = class_store.get_array_class_ref(&array_type_desc).unwrap();
|
||||||
|
|
||||||
|
let array_size = array_capacity * std::mem::size_of::<u8>() + std::mem::size_of::<ByteArray>();
|
||||||
|
|
||||||
|
let array_object = CharArray {
|
||||||
|
class_ref: array_class_ref,
|
||||||
|
content: vec![0; array_capacity].into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let array_ref = self.store_entry(CompartmentEntry::CharArray(array_object));
|
||||||
|
|
||||||
|
(array_ref, array_size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ObjectCompartment {
|
pub struct ObjectCompartment {
|
||||||
|
@ -428,6 +475,7 @@ impl ObjectCompartment {
|
||||||
CompartmentEntry::Object(_) => unreachable!(),
|
CompartmentEntry::Object(_) => unreachable!(),
|
||||||
CompartmentEntry::ReferenceArray(_) => unreachable!(),
|
CompartmentEntry::ReferenceArray(_) => unreachable!(),
|
||||||
CompartmentEntry::ByteArray(_) => unreachable!(),
|
CompartmentEntry::ByteArray(_) => unreachable!(),
|
||||||
|
CompartmentEntry::CharArray(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
*self.objects.get_mut(compartment_index).unwrap() = object;
|
*self.objects.get_mut(compartment_index).unwrap() = object;
|
||||||
|
@ -457,14 +505,21 @@ pub enum CompartmentEntry {
|
||||||
Object(HeapObject),
|
Object(HeapObject),
|
||||||
ReferenceArray(ReferenceArray),
|
ReferenceArray(ReferenceArray),
|
||||||
ByteArray(ByteArray),
|
ByteArray(ByteArray),
|
||||||
|
CharArray(CharArray),
|
||||||
EmptyNext(usize),
|
EmptyNext(usize),
|
||||||
EmptyTail(), // last empty value
|
EmptyTail(), // last empty value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CharArray {
|
||||||
|
class_ref: ObjectReference,
|
||||||
|
content: Box<[u16]>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ByteArray {
|
pub struct ByteArray {
|
||||||
class_ref: ObjectReference,
|
class_ref: ObjectReference,
|
||||||
content: Box<[u8]>,
|
content: Box<[i8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -595,7 +650,7 @@ pub struct ObjectField {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum FieldValue {
|
pub enum FieldValue {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Byte(u8),
|
Byte(i8),
|
||||||
Char(u16),
|
Char(u16),
|
||||||
Short(i16),
|
Short(i16),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
@ -630,7 +685,7 @@ impl FieldValue {
|
||||||
AbstractTypeKind::Long() => Self::Long(0),
|
AbstractTypeKind::Long() => Self::Long(0),
|
||||||
AbstractTypeKind::Classname(_) => Self::Reference(ObjectReference::NULL),
|
AbstractTypeKind::Classname(_) => Self::Reference(ObjectReference::NULL),
|
||||||
AbstractTypeKind::Short() => Self::Short(0),
|
AbstractTypeKind::Short() => Self::Short(0),
|
||||||
AbstractTypeKind::Boolean() => Self::Boolean(true),
|
AbstractTypeKind::Boolean() => Self::Boolean(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
303
src/jvm.rs
303
src/jvm.rs
|
@ -193,7 +193,7 @@ impl JVM {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str) -> ObjectReference {
|
fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str, string_names: bool) -> ObjectReference {
|
||||||
let class_class_index = self.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
let class_class_index = self.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
||||||
let data_class_index = self.class_store.class_idx_from_name(&String::from("::NativeClassData")).unwrap();
|
let data_class_index = self.class_store.class_idx_from_name(&String::from("::NativeClassData")).unwrap();
|
||||||
|
|
||||||
|
@ -209,15 +209,17 @@ impl JVM {
|
||||||
&self.class_store,
|
&self.class_store,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let name_string_ref = self.heap_area.make_handmade_string(&class_name.into(), &self.class_store);
|
if string_names {
|
||||||
// set name string object
|
let name_string_ref = self.heap_area.make_handmade_string(&class_name.into(), &self.class_store);
|
||||||
self.heap_area.object_area.set_object_field(
|
// set name string object
|
||||||
primitive_class_object,
|
self.heap_area.object_area.set_object_field(
|
||||||
"name",
|
primitive_class_object,
|
||||||
FieldValue::Reference(name_string_ref),
|
"name",
|
||||||
class_class_index,
|
FieldValue::Reference(name_string_ref),
|
||||||
&self.class_store,
|
class_class_index,
|
||||||
).unwrap();
|
&self.class_store,
|
||||||
|
).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// set native name index on class data
|
// set native name index on class data
|
||||||
self.heap_area.object_area.set_object_field(
|
self.heap_area.object_area.set_object_field(
|
||||||
|
@ -365,22 +367,7 @@ impl JVM {
|
||||||
|
|
||||||
self.heap_area.fill_byte_cache(&self.class_store);
|
self.heap_area.fill_byte_cache(&self.class_store);
|
||||||
|
|
||||||
self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I");
|
self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B", false);
|
||||||
self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B");
|
|
||||||
self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C");
|
|
||||||
self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J");
|
|
||||||
self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F");
|
|
||||||
self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S");
|
|
||||||
self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D");
|
|
||||||
self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z");
|
|
||||||
|
|
||||||
self.make_array_class(
|
|
||||||
self.class_store.primitive_classes.int_class,
|
|
||||||
AbstractTypeDescription {
|
|
||||||
array_level: 0,
|
|
||||||
kind: AbstractTypeKind::Int(),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
self.make_array_class(
|
self.make_array_class(
|
||||||
self.class_store.primitive_classes.byte_class,
|
self.class_store.primitive_classes.byte_class,
|
||||||
AbstractTypeDescription {
|
AbstractTypeDescription {
|
||||||
|
@ -388,6 +375,39 @@ impl JVM {
|
||||||
kind: AbstractTypeKind::Byte(),
|
kind: AbstractTypeKind::Byte(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
{
|
||||||
|
// we can only make a byte class name after the byte array is loaded
|
||||||
|
let string_ref = self.heap_area.make_handmade_string(&String::from("byte"), &self.class_store);
|
||||||
|
self.heap_area.object_area.set_object_field(
|
||||||
|
self.class_store.primitive_classes.byte_class,
|
||||||
|
"name",
|
||||||
|
FieldValue::Reference(string_ref),
|
||||||
|
class_class_index,
|
||||||
|
&self.class_store
|
||||||
|
).unwrap();
|
||||||
|
}
|
||||||
|
self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I", true);
|
||||||
|
self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C", true);
|
||||||
|
self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J", true);
|
||||||
|
self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F", true);
|
||||||
|
self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S", true);
|
||||||
|
self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D", true);
|
||||||
|
self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z", true);
|
||||||
|
|
||||||
|
self.make_array_class(
|
||||||
|
self.class_store.primitive_classes.char_class,
|
||||||
|
AbstractTypeDescription {
|
||||||
|
array_level: 0,
|
||||||
|
kind: AbstractTypeKind::Char(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self.make_array_class(
|
||||||
|
self.class_store.primitive_classes.int_class,
|
||||||
|
AbstractTypeDescription {
|
||||||
|
array_level: 0,
|
||||||
|
kind: AbstractTypeKind::Int(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
let string_refs = arguments.iter()
|
let string_refs = arguments.iter()
|
||||||
|
@ -533,7 +553,7 @@ impl JVM {
|
||||||
AbstractTypeKind::Byte() => {
|
AbstractTypeKind::Byte() => {
|
||||||
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
|
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
|
||||||
|
|
||||||
FieldValue::Byte(int_entry.value as u8)
|
FieldValue::Byte(int_entry.value as i8)
|
||||||
},
|
},
|
||||||
AbstractTypeKind::Char() => {
|
AbstractTypeKind::Char() => {
|
||||||
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
|
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
|
||||||
|
@ -658,6 +678,14 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::ArithmeticShiftIntRight() => {
|
||||||
|
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111;
|
||||||
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
// rust does arithmetic shift on singed values
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
|
||||||
|
},
|
||||||
|
|
||||||
Instruction::ArrayLength() => {
|
Instruction::ArrayLength() => {
|
||||||
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
|
@ -672,7 +700,7 @@ impl JVM {
|
||||||
|
|
||||||
let element = self.heap_area.object_area.get_array_element(array_reference, element_index);
|
let element = self.heap_area.object_area.get_array_element(array_reference, element_index);
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(element)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Instruction::BranchAlways(branch_offset) => {
|
Instruction::BranchAlways(branch_offset) => {
|
||||||
|
@ -690,6 +718,16 @@ impl JVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::BranchIntGreaterEquals(branch_offset) => {
|
||||||
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
if value_1 >= value_2 {
|
||||||
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::BranchIntInequality(branch_offset) => {
|
Instruction::BranchIntInequality(branch_offset) => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
@ -710,6 +748,16 @@ impl JVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::BranchIntLessThan(branch_offset) => {
|
||||||
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
if value_1 < value_2 {
|
||||||
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::BranchNonNull(branch_offset) => {
|
Instruction::BranchNonNull(branch_offset) => {
|
||||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
|
@ -755,10 +803,10 @@ impl JVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BranchZero(branch_offset) => {
|
Instruction::BranchPositive(branch_offset) => {
|
||||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
if test_value == 0 {
|
if test_value > 0 {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
||||||
}
|
}
|
||||||
|
@ -774,6 +822,35 @@ impl JVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::BranchZero(branch_offset) => {
|
||||||
|
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
if test_value == 0 {
|
||||||
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::CheckCast(classref_index) => {
|
||||||
|
// TODO: Class loading checks
|
||||||
|
let class_name = class.gather_class(classref_index)?;
|
||||||
|
let class_index = self.class_store.class_idx_from_name(class_name).unwrap();
|
||||||
|
let class_object_ref = self.class_store.get_class_objectref_from_index(class_index);
|
||||||
|
let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store);
|
||||||
|
let class_description = AbstractTypeDescription::parse_full(native_class_description)?;
|
||||||
|
|
||||||
|
let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||||
|
let object_description = AbstractTypeDescription::parse_full(native_class_name)?;
|
||||||
|
|
||||||
|
if ! self.class_store.are_types_compatible(&object_description, &class_description) {
|
||||||
|
// TODO: Throw Exception
|
||||||
|
return Err(Error::RunTimeError(format!("Trying to cast an object of type {native_class_name} to {class_name}")))
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(object)))?;
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::CompareFloatG() => {
|
Instruction::CompareFloatG() => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||||
|
@ -886,8 +963,27 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::IncrementLocalInt(index, constant) => {
|
||||||
|
let int = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?;
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int + constant as i32)))?;
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::InstanceOf(classref_index) => {
|
Instruction::InstanceOf(classref_index) => {
|
||||||
|
// TODO: Class loading checks
|
||||||
let class_name = class.gather_class(classref_index)?;
|
let class_name = class.gather_class(classref_index)?;
|
||||||
|
let class_index = self.class_store.class_idx_from_name(class_name).unwrap();
|
||||||
|
let class_object_ref = self.class_store.get_class_objectref_from_index(class_index);
|
||||||
|
let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store);
|
||||||
|
let class_description = AbstractTypeDescription::parse_full(native_class_description)?;
|
||||||
|
|
||||||
|
let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||||
|
let object_description = AbstractTypeDescription::parse_full(native_class_name)?;
|
||||||
|
|
||||||
|
let instruction_result = if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 };
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(instruction_result)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::InvokeSpecial(methodref_index) => {
|
Instruction::InvokeSpecial(methodref_index) => {
|
||||||
|
@ -1041,10 +1137,7 @@ impl JVM {
|
||||||
|
|
||||||
// TODO: Throw error
|
// TODO: Throw error
|
||||||
if ! self.class_store.are_types_compatible(&this_object_descriptor, &base_object_descriptor) {
|
if ! self.class_store.are_types_compatible(&this_object_descriptor, &base_object_descriptor) {
|
||||||
return Err(Error::RunTimeError(format!(
|
return Err(Error::RunTimeError(format!("InvokeVirtual: Cannot call '{base_method_name}' from class '{base_class_name}' on instance from class '{this_object_class_name}: Types are incompatible'")))
|
||||||
"InvokeVirtual: Cannot call '{base_method_name}' from class '{base_class_name}' on instance from class '{}: Types are incompatible'",
|
|
||||||
this_object_class_name
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (invoked_class_index, invoked_method_index, _invoked_method_info) = match ClassMethodIterator::new(this_object_class_index, &self.class_store)
|
let (invoked_class_index, invoked_method_index, _invoked_method_info) = match ClassMethodIterator::new(this_object_class_index, &self.class_store)
|
||||||
|
@ -1076,15 +1169,33 @@ impl JVM {
|
||||||
|
|
||||||
Instruction::LoadByteImmediate(byte) => {
|
Instruction::LoadByteImmediate(byte) => {
|
||||||
// sign extend into int
|
// sign extend into int
|
||||||
let i8_int = i8::from_be_bytes([byte]);
|
|
||||||
|
|
||||||
let frame_result = frame.operand_stack.push(StackValue::Int(i8_int as i32));
|
let frame_result = frame.operand_stack.push(StackValue::Int(byte as i32));
|
||||||
match frame_result {
|
match frame_result {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
|
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::LoadShortImmediate(short) => {
|
||||||
|
// sign extend into int
|
||||||
|
|
||||||
|
let frame_result = frame.operand_stack.push(StackValue::Int(short as i32));
|
||||||
|
match frame_result {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::LoadFromBArray() => {
|
||||||
|
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let array = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
|
let element = self.heap_area.object_area.get_array_element(array, index);
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?;
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::LoadConstant(index) => {
|
Instruction::LoadConstant(index) => {
|
||||||
// TODO: Handle error instead of unwrap
|
// TODO: Handle error instead of unwrap
|
||||||
match class.pool_entry(index as u16).unwrap() {
|
match class.pool_entry(index as u16).unwrap() {
|
||||||
|
@ -1185,13 +1296,19 @@ impl JVM {
|
||||||
let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store);
|
let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store);
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
|
||||||
},
|
}
|
||||||
|
|
||||||
|
ConstantPoolInfo::Integer(int_data) => {
|
||||||
|
let int_value = int_data.value;
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("{:?}", class.pool_entry(wide_index).unwrap());
|
println!("{:?}", class.pool_entry(wide_index).unwrap());
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
Instruction::LoadLocalFloat0() => {
|
Instruction::LoadLocalFloat0() => {
|
||||||
load_local_float(class, method, frame, 0)?;
|
load_local_float(class, method, frame, 0)?;
|
||||||
|
@ -1219,6 +1336,9 @@ impl JVM {
|
||||||
load_local_int(class, method, frame, 3)?;
|
load_local_int(class, method, frame, 3)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::LoadLocalReference(index) => {
|
||||||
|
load_local_reference(class, method, frame, index as usize)?;
|
||||||
|
}
|
||||||
Instruction::LoadLocalReference0() => {
|
Instruction::LoadLocalReference0() => {
|
||||||
load_local_reference(class, method, frame, 0)?;
|
load_local_reference(class, method, frame, 0)?;
|
||||||
}
|
}
|
||||||
|
@ -1232,6 +1352,27 @@ impl JVM {
|
||||||
load_local_reference(class, method, frame, 3)?;
|
load_local_reference(class, method, frame, 3)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::LogicalShiftIntRight() => {
|
||||||
|
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111;
|
||||||
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let uint = u32::from_ne_bytes(int.to_ne_bytes());
|
||||||
|
let u_result = uint >> shift;
|
||||||
|
let i_result = i32::from_ne_bytes(u_result.to_ne_bytes());
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(i_result)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::LookupSwitch(default_offset, pairs) => {
|
||||||
|
let key = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let jump_offset = match pairs.binary_search_by(|(match_key, _offset)| match_key.cmp(&key)) {
|
||||||
|
Ok(offset) => pairs[offset].1,
|
||||||
|
Err(_) => default_offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
frame.instruction_pointer = if jump_offset < 0 { frame.instruction_pointer - jump_offset.abs() as u32} else { frame.instruction_pointer + jump_offset.abs() as u32};
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::MultiplyInt() => {
|
Instruction::MultiplyInt() => {
|
||||||
let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
@ -1283,6 +1424,7 @@ impl JVM {
|
||||||
Instruction::NewPrimitiveArray(array_type) => {
|
Instruction::NewPrimitiveArray(array_type) => {
|
||||||
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
const CHAR: u8 = 5;
|
||||||
const BYTE: u8 = 8;
|
const BYTE: u8 = 8;
|
||||||
let array_ref = match array_type {
|
let array_ref = match array_type {
|
||||||
BYTE => {
|
BYTE => {
|
||||||
|
@ -1291,6 +1433,12 @@ impl JVM {
|
||||||
array_ref
|
array_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHAR => {
|
||||||
|
let array_ref = self.heap_area.make_primitive_char_array(array_capacity as usize, &self.class_store);
|
||||||
|
|
||||||
|
array_ref
|
||||||
|
}
|
||||||
|
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1333,6 +1481,9 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(2.0)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(2.0)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::PushConstIntM1() => {
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(-1)))?;
|
||||||
|
}
|
||||||
Instruction::PushConstInt0() => {
|
Instruction::PushConstInt0() => {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
|
||||||
}
|
}
|
||||||
|
@ -1364,6 +1515,7 @@ impl JVM {
|
||||||
_ => match wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))? {
|
_ => match wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))? {
|
||||||
StackValue::Int(i) => FieldValue::Int(i),
|
StackValue::Int(i) => FieldValue::Int(i),
|
||||||
StackValue::Reference(r) => FieldValue::Reference(r),
|
StackValue::Reference(r) => FieldValue::Reference(r),
|
||||||
|
StackValue::Float(f) => FieldValue::Float(f),
|
||||||
stack_value @ _ => {
|
stack_value @ _ => {
|
||||||
println!("{stack_value:?}");
|
println!("{stack_value:?}");
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -1427,20 +1579,26 @@ impl JVM {
|
||||||
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
if ref_value != ObjectReference::NULL {
|
if ref_value != ObjectReference::NULL {
|
||||||
let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store);
|
let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store);
|
||||||
let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1;
|
let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1;
|
||||||
|
|
||||||
if ! self.class_store.are_types_compatible(&matched_field.descriptor, &parsed_native_name) {
|
if ! self.class_store.are_types_compatible(&parsed_native_name, &matched_field.descriptor) {
|
||||||
return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor)));
|
return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldValue::Reference(ref_value)
|
FieldValue::Reference(ref_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(1..=255, _) => {
|
||||||
|
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
FieldValue::Reference(ref_value)
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
println!("{:?}", matched_field);
|
println!("{:?}", matched_field);
|
||||||
todo!()
|
todo!()
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
|
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
|
||||||
|
@ -1479,13 +1637,6 @@ impl JVM {
|
||||||
return Ok(JVMCallbackOperation::PopFrame());
|
return Ok(JVMCallbackOperation::PopFrame());
|
||||||
},
|
},
|
||||||
|
|
||||||
Instruction::ShiftIntRight() => {
|
|
||||||
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111;
|
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
|
|
||||||
},
|
|
||||||
|
|
||||||
Instruction::StoreIntoBArray() => {
|
Instruction::StoreIntoBArray() => {
|
||||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
@ -1493,7 +1644,7 @@ impl JVM {
|
||||||
|
|
||||||
match self.heap_area.object_area.get_entry(array_ref) {
|
match self.heap_area.object_area.get_entry(array_ref) {
|
||||||
CompartmentEntry::ByteArray(_) => {
|
CompartmentEntry::ByteArray(_) => {
|
||||||
let byte_value = value.to_ne_bytes()[3];
|
let byte_value = value as i8;
|
||||||
|
|
||||||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Byte(byte_value));
|
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Byte(byte_value));
|
||||||
}
|
}
|
||||||
|
@ -1501,6 +1652,22 @@ impl JVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::StoreIntoCArray() => {
|
||||||
|
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
|
match self.heap_area.object_area.get_entry(array_ref) {
|
||||||
|
CompartmentEntry::CharArray(_) => {
|
||||||
|
let int_bytes = value.to_ne_bytes();
|
||||||
|
let char_value = u16::from_ne_bytes([int_bytes[2], int_bytes[3]]);
|
||||||
|
|
||||||
|
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Char(char_value));
|
||||||
|
}
|
||||||
|
_ => todo!(), // TODO: Handle as error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::StoreIntoRArray() => {
|
Instruction::StoreIntoRArray() => {
|
||||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
@ -1511,52 +1678,64 @@ impl JVM {
|
||||||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value));
|
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::SubtractInt() => {
|
||||||
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 - value_2)))?;
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::StoreLocalInt(index) => {
|
Instruction::StoreLocalInt(index) => {
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int)))?;
|
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreLocalInt0() => {
|
Instruction::StoreLocalInt0() => {
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?;
|
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreLocalInt1() => {
|
Instruction::StoreLocalInt1() => {
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Int(int)))?;
|
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Int(int)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreLocalInt2() => {
|
Instruction::StoreLocalInt2() => {
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Int(int)))?;
|
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Int(int)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreLocalInt3() => {
|
Instruction::StoreLocalInt3() => {
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?;
|
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?;
|
||||||
},
|
}
|
||||||
|
|
||||||
Instruction::StoreReference0() => {
|
Instruction::StoreLocalReference(index) => {
|
||||||
|
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Reference(reference)))?;
|
||||||
|
}
|
||||||
|
Instruction::StoreLocalReference0() => {
|
||||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Reference(reference)))?;
|
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Reference(reference)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreReference1() => {
|
Instruction::StoreLocalReference1() => {
|
||||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Reference(reference)))?;
|
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Reference(reference)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreReference2() => {
|
Instruction::StoreLocalReference2() => {
|
||||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Reference(reference)))?;
|
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Reference(reference)))?;
|
||||||
},
|
}
|
||||||
Instruction::StoreReference3() => {
|
Instruction::StoreLocalReference3() => {
|
||||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Reference(reference)))?;
|
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Reference(reference)))?;
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
|
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
|
||||||
|
|
|
@ -15,11 +15,13 @@ mod native_methods;
|
||||||
//use crate::accessmasks::FieldAccessFlag;
|
//use crate::accessmasks::FieldAccessFlag;
|
||||||
//use crate::stackframe::StackValue;
|
//use crate::stackframe::StackValue;
|
||||||
//use crate::classfile::JavaClassFile;
|
//use crate::classfile::JavaClassFile;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/System.class").unwrap()).unwrap());
|
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/System.class").unwrap()).unwrap());
|
||||||
|
|
||||||
let mut jvm = jvm::JVM::new();
|
let mut jvm = jvm::JVM::new();
|
||||||
|
jvm.class_store.class_path_fragments.push(PathBuf::from("./classpath"));
|
||||||
|
|
||||||
match jvm.entrypoint(
|
match jvm.entrypoint(
|
||||||
&"Main".to_string(),
|
&"Main".to_string(),
|
||||||
|
|
|
@ -49,6 +49,8 @@ impl JavaLangClass {
|
||||||
};
|
};
|
||||||
// max_locals: 1
|
// max_locals: 1
|
||||||
// max_stack: 1
|
// max_stack: 1
|
||||||
|
let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap();
|
||||||
|
let method = &class.methods[frame.method_index as usize];
|
||||||
let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
||||||
let (string_class_file, string_class_index) = jvm.class_store.get_class(&String::from("java/lang/String")).unwrap();
|
let (string_class_file, string_class_index) = jvm.class_store.get_class(&String::from("java/lang/String")).unwrap();
|
||||||
let string_equals_index = string_class_file.find_method_index(&String::from("equals")).unwrap();
|
let string_equals_index = string_class_file.find_method_index(&String::from("equals")).unwrap();
|
||||||
|
@ -57,7 +59,9 @@ impl JavaLangClass {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match frame.instruction_pointer {
|
frame.instruction_pointer += 1;
|
||||||
|
|
||||||
|
match frame.instruction_pointer - 1 {
|
||||||
0 => {
|
0 => {
|
||||||
let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class;
|
let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class;
|
||||||
let boolean_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
let boolean_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
@ -77,10 +81,206 @@ impl JavaLangClass {
|
||||||
&[StackValue::Reference(boolean_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
&[StackValue::Reference(boolean_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
);
|
);
|
||||||
|
|
||||||
frame.instruction_pointer += 1;
|
|
||||||
|
|
||||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
},
|
}
|
||||||
|
|
||||||
|
1 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(boolean_class_ref)))
|
||||||
|
} else {
|
||||||
|
let byte_class_ref = jvm.class_store.primitive_classes.byte_class;
|
||||||
|
let byte_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
byte_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(byte_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
2 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let char_class_ref = jvm.class_store.primitive_classes.char_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(char_class_ref)))
|
||||||
|
} else {
|
||||||
|
let char_class_ref = jvm.class_store.primitive_classes.char_class;
|
||||||
|
let char_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
char_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(char_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
3 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let short_class_ref = jvm.class_store.primitive_classes.short_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(short_class_ref)))
|
||||||
|
} else {
|
||||||
|
let short_class_ref = jvm.class_store.primitive_classes.short_class;
|
||||||
|
let short_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
short_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(short_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
4 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let int_class_ref = jvm.class_store.primitive_classes.int_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(int_class_ref)))
|
||||||
|
} else {
|
||||||
|
let int_class_ref = jvm.class_store.primitive_classes.int_class;
|
||||||
|
let int_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
int_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(int_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
5 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let float_class_ref = jvm.class_store.primitive_classes.float_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(float_class_ref)))
|
||||||
|
} else {
|
||||||
|
let float_class_ref = jvm.class_store.primitive_classes.float_class;
|
||||||
|
let float_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
float_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(float_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
6 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let double_class_ref = jvm.class_store.primitive_classes.double_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(double_class_ref)))
|
||||||
|
} else {
|
||||||
|
let double_class_ref = jvm.class_store.primitive_classes.double_class;
|
||||||
|
let double_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
double_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(double_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
7 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let long_class_ref = jvm.class_store.primitive_classes.long_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref)))
|
||||||
|
} else {
|
||||||
|
let long_class_ref = jvm.class_store.primitive_classes.long_class;
|
||||||
|
let long_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||||
|
long_class_ref,
|
||||||
|
"name",
|
||||||
|
class_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_compare_frame = StackFrame::new(
|
||||||
|
string_class_file,
|
||||||
|
string_class_index,
|
||||||
|
string_equals_index as u16,
|
||||||
|
&[StackValue::Reference(long_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
8 => {
|
||||||
|
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||||
|
let long_class_ref = jvm.class_store.primitive_classes.long_class;
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref)))
|
||||||
|
} else {
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL)))
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL)))
|
_ => Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +290,14 @@ impl JavaLangClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct JavaLangStringUTF16 {}
|
||||||
|
|
||||||
|
impl JavaLangStringUTF16 {
|
||||||
|
pub fn is_big_endian(_jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(if cfg!(target_endian = "big") {1} else {0})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct JdkInternalMiscUnsafe {}
|
struct JdkInternalMiscUnsafe {}
|
||||||
|
|
||||||
impl JdkInternalMiscUnsafe {
|
impl JdkInternalMiscUnsafe {
|
||||||
|
@ -157,8 +365,19 @@ impl JdkInternalUtilSystemPropsRaw {
|
||||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// command-line configured properties, should return at least java.home
|
||||||
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, 2);
|
let array_length = 4;
|
||||||
|
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, array_length);
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: Actual java home path
|
||||||
|
let java_home_key_reference = jvm.heap_area.make_handmade_string(&String::from("java.home"), &jvm.class_store);
|
||||||
|
let java_home_value_reference = jvm.heap_area.make_handmade_string(&String::from("./"), &jvm.class_store);
|
||||||
|
|
||||||
|
jvm.heap_area.object_area.set_array_element(array_reference, 0, java_home_key_reference.into());
|
||||||
|
jvm.heap_area.object_area.set_array_element(array_reference, 1, java_home_value_reference.into());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
|
||||||
}
|
}
|
||||||
|
@ -696,6 +915,20 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
Ok(todo_call)
|
Ok(todo_call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
("java/lang/StringUTF16", "isBigEndian") => {
|
||||||
|
// until JDK 23
|
||||||
|
let expected_descriptor = MethodDescriptor {
|
||||||
|
argument_types: Box::new([]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
||||||
|
};
|
||||||
|
|
||||||
|
if m.descriptor != expected_descriptor {
|
||||||
|
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(JavaLangStringUTF16::is_big_endian)
|
||||||
|
}
|
||||||
|
|
||||||
("java/lang/Object", "clone") => {
|
("java/lang/Object", "clone") => {
|
||||||
let expected_descriptor = MethodDescriptor {
|
let expected_descriptor = MethodDescriptor {
|
||||||
argument_types: Box::new([]),
|
argument_types: Box::new([]),
|
||||||
|
|
Loading…
Reference in a new issue