Skip to content

Commit 7b12b0a

Browse files
committed
Added switch support. Updated README in preparation for 0.1
1 parent 4517710 commit 7b12b0a

File tree

14 files changed

+68
-158
lines changed

14 files changed

+68
-158
lines changed

README.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# What is `jtcpp`
2-
`jtcpp` is a versatile, highly experimental JVM bytecode to C++ converter. It generates C++ code which an exact, JVM op into C++ statement, translation of the input bytecode. This approach has some limitations, which may reduce performance of generated C++ code. This makes general comparisons between speed original Java code and translated C++ very hard, because it varies so much(From 3x speedup to 50x slowdown).
2+
Disclaimer:
3+
*`jtcpp` was created as a learning exercise, and a way to better understand both JVM bytcode and Java class format. It is a proof of concept, and not meant to be used for anything besides exploring the idea of compiling languages using JVM to native code.*
4+
`jtcpp` is a versatile, highly experimental JVM bytecode to C++ transpiler. It generates C++ code which an exact, JVM op into C++ statement, translation of the input bytecode. This approach has some limitations, which may reduce performance of generated C++ code. This makes general comparisons between speed original Java code and translated C++ very hard, because it varies so much(From 3x speedup to 50x slowdown).
35
# Compatibility.
46
Building `jtcpp` is supported only on Linux. `make`,`cmake`,`git` and either `g++` or `clang` is required.
57
Translated `C++` code should work with almost any compiler. It was tested with both `g++` and `clang`, and minimal supported C++ version is C++ 11.
@@ -20,7 +22,22 @@ NOTE:All translated dependencies should have the same target directory
2022
`jtcpp` ships with a minimal, bare-bones implementation of java standard library. The shipped version of the standard library is meant only for testing, and contains only support for classes such as `String`, `Object`, `System` and `PrintStream`, required for outputting to console. Those classes contain only implementations of strictly necessary methods.
2123
# Java features
2224
`jtcpp` supports object creation, 1D arrays, inheritance, static and virtual methods. Support for generics is partial and they may not always work.
23-
`jtcpp` does not support multi dimensional arrays, interfaces, switch statements, exception handling.
25+
`jtcpp` does not support multi dimensional arrays, interfaces, exception handling.
2426
# JVM bytcode Ops
25-
`jtcpp` currently supports almost all JVM opcodes, besides: `tableswitch`, `lookupswitch` `dup2_x2`, `multanewarray`, `invokedynamic`.
27+
`jtcpp` currently supports almost all JVM opcodes, besides: `dup2_x2`, `multanewarray`, and `invokedynamic`.
28+
# Building some examples
29+
In order to test out some examples(they are in `test` directory), compile them using `javac`. Then, invoke jtcpp with resulting `.class` files as source files for transpilation. Go to the resulting target directory, and run `make`.
30+
After that, you should have a naively compiled version of input program.
31+
32+
Beware! Some of examples do not work on purpose, to show what is currently missing. Examples which do not work have a comment at their top, explaing exactly why they do not work yet.
33+
Example of building an example:
34+
`cd test/nbody`
35+
`javac NBody`
36+
`cd ../..`
37+
`jtcpp --out target/nbody -s test/nbody/Planet.class -s test/nbody/Vector3.class -s test/nbody/NBody.class -s test/nbody/Rand.class`
38+
`cd target/nbody`
39+
`make`
40+
`cd build`
41+
`./translated.out`
42+
And you should see positions and velocities of simulated bodies being printed.
2643

src/cpp_codegen/method.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,21 @@ fn write_op(op: &FatOp, mw: &mut MethodWriter) {
10491049
_=>panic!("Invoke Dynamic requires runtime codegen, which is not supported!"),
10501050
}
10511051
}
1052-
FatOp::Dup2X2 | &FatOp::MultiANewArray(_, _) | &FatOp::LookupSwitch { .. } => todo!(),
1052+
FatOp::LookupSwitch{default_op,pairs}=>{
1053+
let (key_type,key) = mw.vstack_pop().unwrap();
1054+
assert!(VariableType::Int.assignable(&key_type));
1055+
mw.write_raw(&format!("switch ({key})"));
1056+
mw.begin_scope();
1057+
for (key,target) in pairs.iter(){
1058+
mw.write_raw(&format!("case {key}:"));
1059+
mw.write_raw(&format!("\tgoto bb{target};"));
1060+
}
1061+
mw.write_raw("default:");
1062+
mw.write_raw(&format!("\tgoto bb{default_op};"));
1063+
mw.end_scope();
1064+
"".into()
1065+
},
1066+
FatOp::Dup2X2 | &FatOp::MultiANewArray(_, _) => todo!(),
10531067
//_ => todo!("Unsuported op:\"{op:?}\""),
10541068
};
10551069
mw.write_op(op, &code);

src/cpp_codegen/method_writer.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,18 @@ impl MethodWriter {
9393
pub(crate) fn set_sig(&mut self, sig: &str) {
9494
self.sig = sig.into();
9595
}
96+
pub(crate) fn write_raw(&mut self, code: &str){
97+
self.write_ident();
98+
self.code.push_str(code);
99+
self.code.push('\n');
100+
}
96101
pub(crate) fn write_op(&mut self, curr_op: &FatOp, code: &str) {
97102
if self.use_debuginfo() {
98103
self.write_ident();
99104
self.code.push_str(&format!("//{curr_op:?}\n"));
100105
}
101106
if code != ""{
102-
self.write_ident();
103-
self.code.push_str(code);
104-
self.code.push('\n');
107+
self.write_raw(code);
105108
}
106109
}
107110
pub(crate) fn vstack_push(&mut self, vvar: &str, vtype: VariableType) {

src/importer/opcodes.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,30 @@ pub(crate) fn load_ops<R: std::io::Read>(
442442
}))
443443
}
444444
0xaa => {
445-
return Err(std::io::Error::new(
446-
std::io::ErrorKind::Other,
447-
"Table switch op not supported!",
448-
));
445+
let to_next = ((4 - curr_offset % 4) % 4) as usize;
446+
// skip to_next
447+
let mut out = [0; 4];
448+
src.read_exact(&mut out[..to_next])?;
449+
curr_offset += to_next as u16;
450+
assert_eq!(curr_offset % 4, 0);
451+
let default_offset = load_i32(src)?;
452+
curr_offset += 4 as u16;
453+
let low = load_i32(src)?;
454+
curr_offset += 4 as u16;
455+
let high = load_i32(src)?;
456+
curr_offset += 4 as u16;
457+
let count = (high - low + 1);
458+
let mut pairs = Vec::with_capacity(count as usize);
459+
for key in 0..count{
460+
let curr_key:i32 = key - low;
461+
let offset = load_i32(src)?;
462+
curr_offset += 4 as u16;
463+
pairs.push((curr_key,offset));
464+
}
465+
OpCode::LookupSwitch(Box::new(LookupSwitch {
466+
default_offset,
467+
pairs: pairs.into(),
468+
}))
449469
}
450470
0xac => OpCode::IReturn,
451471
0xad => OpCode::LReturn,

test/BasicArthm.java

Lines changed: 0 additions & 30 deletions
This file was deleted.

test/Calls.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

test/Extends.java

Lines changed: 0 additions & 8 deletions
This file was deleted.

test/Fields.java

Lines changed: 0 additions & 7 deletions
This file was deleted.

test/Gravity.java

Lines changed: 0 additions & 33 deletions
This file was deleted.

test/HTTPServer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//This example can be transpiled, but produced C++ does not yet compile, since the C++ implementation of the stdlib does not support Charsets.
12
import java.net.Socket;
23
import java.net.ServerSocket;
34
import java.io.OutputStream;

test/Identity.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

test/Interfaces.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Interfaces don't yet work!
12
interface Animal{
23
public void Sound();
34
}

test/InvokeDynamic.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// This example uses lambdas, which use `InvokeDynamic` op under the hood.
12
import java.util.List;
23
class InvokeDynamic {
34
public static void main(String[] args) {

test/interface/Animals.java

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)