1use crate::{
4 adapters::FunctionMapper,
5 backends::{Backend, GeneratedFiles},
6 config::GaiaConfig,
7 instruction::{CoreInstruction, GaiaInstruction},
8 program::{GaiaConstant, GaiaFunction, GaiaGlobal, GaiaModule},
9 types::{GaiaType, mapping},
10};
11use gaia_types::{
12 helpers::{AbiCompatible, ApiCompatible, Architecture, ArtifactType, CompilationTarget},
13 GaiaError, Result,
14};
15use std::collections::HashMap;
16
17#[cfg(feature = "jvm-assembler")]
18use jvm_assembler::{
19 formats::class::writer::ClassWriter,
20 program::{JvmAccessFlags, JvmField, JvmInstruction, JvmMethod, JvmProgram, JvmVersion, JvmExceptionHandler},
21};
22
23#[cfg(not(feature = "jvm-assembler"))]
24mod jvm_stub {
25 pub struct JvmProgram;
26}
27#[cfg(not(feature = "jvm-assembler"))]
28use jvm_stub::*;
29
30#[derive(Default)]
32pub struct JvmBackend {}
33
34impl Backend for JvmBackend {
35 fn name(&self) -> &'static str {
36 "JVM"
37 }
38
39 fn primary_target(&self) -> CompilationTarget {
40 CompilationTarget { build: Architecture::JVM, host: AbiCompatible::Unknown, target: ApiCompatible::JvmRuntime(8) }
41 }
42
43 fn artifact_type(&self) -> ArtifactType {
44 ArtifactType::Bytecode
45 }
46
47 fn match_score(&self, target: &CompilationTarget) -> f32 {
48 match target.build {
49 Architecture::JVM => match target.host {
50 AbiCompatible::Unknown => 80.0,
52 AbiCompatible::JavaAssembly => 5.0,
54 _ => -100.0,
55 },
56 _ => -100.0,
57 }
58 }
59
60 fn generate(&self, program: &GaiaModule, config: &GaiaConfig) -> Result<GeneratedFiles> {
61 #[cfg(feature = "jvm-assembler")]
62 {
63 let mut files = HashMap::new();
64
65 let jvm_program = convert_gaia_to_jvm(program, config)?;
67
68 match config.target.host {
69 AbiCompatible::Unknown => {
70 let buffer = Vec::new();
72 let class_writer = ClassWriter::new(buffer);
73 let class_bytes = class_writer.write(&jvm_program).result?;
74 files.insert("main.class".to_string(), class_bytes);
75 }
76 AbiCompatible::JavaAssembly => {
77 return Err(GaiaError::custom_error("JASM output is currently disabled"));
78 }
79 _ => return Err(GaiaError::custom_error(&format!("Unsupported host ABI: {:?}", config.target.host))),
80 }
81
82 Ok(GeneratedFiles { artifact_type: self.artifact_type(), files, custom: None, diagnostics: vec![] })
83 }
84 #[cfg(not(feature = "jvm-assembler"))]
85 {
86 let _ = program;
87 let _ = config;
88 Err(gaia_types::errors::GaiaError::custom_error("JVM backend not enabled"))
89 }
90 }
91}
92
93impl JvmBackend {
94 pub fn generate_program(program: &GaiaModule) -> Result<JvmProgram> {
96 #[cfg(feature = "jvm-assembler")]
97 {
98 let default_config = GaiaConfig::default();
100 convert_gaia_to_jvm(program, &default_config)
101 }
102 #[cfg(not(feature = "jvm-assembler"))]
103 {
104 let _ = program;
105 Err(gaia_types::errors::GaiaError::custom_error("JVM backend not enabled"))
106 }
107 }
108}
109
110#[cfg(feature = "jvm-assembler")]
111struct JvmContext {
113 function_mapper: FunctionMapper,
114 field_types: HashMap<(String, String), String>,
116}
117
118#[cfg(feature = "jvm-assembler")]
119fn convert_gaia_to_jvm(program: &GaiaModule, config: &GaiaConfig) -> Result<JvmProgram> {
121 let mut jvm_program = JvmProgram::new(program.name.clone());
122
123 jvm_program.version = JvmVersion { major: 52, minor: 0 }; jvm_program.access_flags = JvmAccessFlags::public();
128
129 let mut field_types = HashMap::new();
131 for class in &program.classes {
132 for field in &class.fields {
133 field_types.insert((class.name.clone(), field.name.clone()), convert_gaia_type_to_jvm_descriptor(&field.ty));
134 }
135 }
136 for global in &program.globals {
137 field_types.insert(("Main".to_string(), global.name.clone()), convert_gaia_type_to_jvm_descriptor(&global.ty));
138 }
139
140 let ctx = JvmContext { function_mapper: FunctionMapper::from_config(&config.setting)?, field_types };
142
143 for function in &program.functions {
145 let jvm_method = convert_gaia_function_to_jvm(function, &ctx)?;
146 jvm_program.add_method(jvm_method);
147 }
148
149 for class in &program.classes {
151 for field in &class.fields {
152 let jvm_field = convert_gaia_field_to_jvm_field(field)?;
153 jvm_program.add_field(jvm_field);
154 }
155 for method in &class.methods {
156 let jvm_method = convert_gaia_function_to_jvm(method, &ctx)?;
157 jvm_program.add_method(jvm_method);
158 }
159 }
160
161 for global in &program.globals {
163 let jvm_field = convert_gaia_global_to_jvm_field(global)?;
164 jvm_program.add_field(jvm_field);
165 }
166
167 Ok(jvm_program)
168}
169
170#[cfg(feature = "jvm-assembler")]
171fn convert_gaia_function_to_jvm(function: &GaiaFunction, ctx: &JvmContext) -> Result<JvmMethod> {
173 let descriptor = build_method_descriptor(&function.signature.params, &Some(function.signature.return_type.clone()));
175
176 let mut method = JvmMethod::new(function.name.clone(), descriptor);
177
178 method.access_flags.is_public = true;
180 method.access_flags.is_static = true;
181
182 let mut try_blocks: Vec<()> = vec![];
184
185 for block in &function.blocks {
187 if !block.label.is_empty() {
189 method.add_instruction(JvmInstruction::Label { name: block.label.clone() });
190 }
191
192 let mut block_instructions = vec![];
194 for instruction in &block.instructions {
195 block_instructions.push(instruction.clone());
196 }
197
198 let optimized_block_instructions = constant_fold(&block_instructions);
200 let optimized_block_instructions = eliminate_dead_code(&optimized_block_instructions);
201
202 for instruction in &optimized_block_instructions {
204 match instruction {
205 _ => {
207 let converted = convert_gaia_instruction_to_jvm(instruction, ctx)?;
208 for instr in converted {
209 method.add_instruction(instr);
210 }
211 }
212 }
213 }
214
215 let mut terminator_instructions = vec![];
217 match &block.terminator {
218 crate::program::GaiaTerminator::Jump(label) => {
219 terminator_instructions.push(JvmInstruction::Goto { target: label.clone() });
220 }
221 crate::program::GaiaTerminator::Branch { true_label, false_label } => {
222 terminator_instructions.push(JvmInstruction::Ifne { target: true_label.clone() });
224 terminator_instructions.push(JvmInstruction::Goto { target: false_label.clone() });
225 }
226 crate::program::GaiaTerminator::Return => {
227 match function.signature.return_type {
229 GaiaType::I32 | GaiaType::U32 | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 | GaiaType::Bool => {
230 terminator_instructions.push(JvmInstruction::Ireturn);
231 }
232 GaiaType::I64 | GaiaType::U64 => {
233 terminator_instructions.push(JvmInstruction::Lreturn);
234 }
235 GaiaType::F32 => {
236 terminator_instructions.push(JvmInstruction::Freturn);
237 }
238 GaiaType::F64 => {
239 terminator_instructions.push(JvmInstruction::Dreturn);
240 }
241 _ => {
242 terminator_instructions.push(JvmInstruction::Areturn);
243 }
244 }
245 }
246 crate::program::GaiaTerminator::Call { callee, args_count: _, next_block } => {
247 let jvm_target = CompilationTarget {
249 build: Architecture::JVM,
250 host: AbiCompatible::JavaAssembly,
251 target: ApiCompatible::JvmRuntime(8),
252 };
253 let mapped = ctx.function_mapper.map_function(&jvm_target, callee).unwrap_or(callee.as_str()).to_string();
254
255 terminator_instructions.push(JvmInstruction::Invokestatic {
256 class_name: "Main".to_string(),
257 method_name: mapped,
258 descriptor: "()V".to_string(), });
260 terminator_instructions.push(JvmInstruction::Goto { target: next_block.clone() });
261 }
262 crate::program::GaiaTerminator::Halt => {
263 terminator_instructions.push(JvmInstruction::Iconst0);
265 terminator_instructions.push(JvmInstruction::Invokestatic {
266 class_name: "java/lang/System".to_string(),
267 method_name: "exit".to_string(),
268 descriptor: "(I)V".to_string(),
269 });
270 }
271 }
272
273 let optimized_terminator_instructions = optimize_jvm_instructions(terminator_instructions);
275
276 for instr in optimized_terminator_instructions {
278 method.add_instruction(instr);
279 }
280 }
281
282 let (max_stack, max_locals) = calculate_stack_and_locals(function, ctx)?;
284 method.max_stack = max_stack;
285 method.max_locals = max_locals;
286
287 Ok(method)
288}
289
290#[cfg(feature = "jvm-assembler")]
291fn convert_gaia_field_to_jvm_field(field: &crate::program::GaiaField) -> Result<JvmField> {
293 let descriptor = convert_gaia_type_to_jvm_descriptor(&field.ty);
294 let mut jvm_field = JvmField::new(field.name.clone(), descriptor);
295
296 if field.is_static {
297 jvm_field.access_flags.is_static = true;
298 }
299
300 match field.visibility {
301 crate::program::Visibility::Public => jvm_field.access_flags.is_public = true,
302 crate::program::Visibility::Private => jvm_field.access_flags.is_private = true,
303 crate::program::Visibility::Protected => jvm_field.access_flags.is_protected = true,
304 _ => {}
305 }
306
307 Ok(jvm_field)
308}
309
310#[cfg(feature = "jvm-assembler")]
311fn convert_gaia_global_to_jvm_field(global: &GaiaGlobal) -> Result<JvmField> {
313 let descriptor = convert_gaia_type_to_jvm_descriptor(&global.ty);
314 let mut field = JvmField::new(global.name.clone(), descriptor);
315 field.access_flags.is_public = true;
316 field.access_flags.is_static = true;
317
318 Ok(field)
319}
320
321#[cfg(feature = "jvm-assembler")]
322fn constant_fold(instructions: &[GaiaInstruction]) -> Vec<GaiaInstruction> {
324 let mut optimized = vec![];
325 let mut i = 0;
326
327 while i < instructions.len() {
328 if i + 2 < instructions.len() {
330 if let (GaiaInstruction::Core(CoreInstruction::PushConstant(c1)),
331 GaiaInstruction::Core(CoreInstruction::PushConstant(c2)),
332 GaiaInstruction::Core(op)) = (&instructions[i], &instructions[i+1], &instructions[i+2]) {
333 match op {
334 CoreInstruction::Add(ty) => {
335 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a + b) {
336 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
337 i += 3;
338 continue;
339 }
340 }
341 CoreInstruction::Sub(ty) => {
342 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a - b) {
343 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
344 i += 3;
345 continue;
346 }
347 }
348 CoreInstruction::Mul(ty) => {
349 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a * b) {
350 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
351 i += 3;
352 continue;
353 }
354 }
355 CoreInstruction::Div(ty) => {
356 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a / b) {
357 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
358 i += 3;
359 continue;
360 }
361 }
362 CoreInstruction::Rem(ty) => {
363 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a % b) {
364 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
365 i += 3;
366 continue;
367 }
368 }
369 CoreInstruction::And(ty) => {
370 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a & b) {
371 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
372 i += 3;
373 continue;
374 }
375 }
376 CoreInstruction::Or(ty) => {
377 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a | b) {
378 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
379 i += 3;
380 continue;
381 }
382 }
383 CoreInstruction::Xor(ty) => {
384 if let (Some(result), _) = evaluate_binary_op(c1, c2, |a, b| a ^ b) {
385 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
386 i += 3;
387 continue;
388 }
389 }
390 _ => {}
391 }
392 }
393 }
394
395 if i + 1 < instructions.len() {
397 if let (GaiaInstruction::Core(CoreInstruction::PushConstant(c)),
398 GaiaInstruction::Core(op)) = (&instructions[i], &instructions[i+1]) {
399 match op {
400 CoreInstruction::Neg(ty) => {
401 if let Some(result) = evaluate_unary_op(c, |a| -a) {
402 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
403 i += 2;
404 continue;
405 }
406 }
407 CoreInstruction::Not(ty) => {
408 if let Some(result) = evaluate_unary_op(c, |a| !a) {
409 optimized.push(GaiaInstruction::Core(CoreInstruction::PushConstant(result)));
410 i += 2;
411 continue;
412 }
413 }
414 _ => {}
415 }
416 }
417 }
418
419 optimized.push(instructions[i].clone());
420 i += 1;
421 }
422
423 optimized
424}
425
426#[cfg(feature = "jvm-assembler")]
427fn evaluate_binary_op<F>(c1: &GaiaConstant, c2: &GaiaConstant, op: F) -> (Option<GaiaConstant>, GaiaType)
429where F: Fn(i64, i64) -> i64 {
430 match (c1, c2) {
431 (GaiaConstant::I32(a), GaiaConstant::I32(b)) => {
432 let result = op(*a as i64, *b as i64);
433 (Some(GaiaConstant::I32(result as i32)), GaiaType::I32)
434 }
435 (GaiaConstant::I64(a), GaiaConstant::I64(b)) => {
436 let result = op(*a, *b);
437 (Some(GaiaConstant::I64(result)), GaiaType::I64)
438 }
439 (GaiaConstant::U32(a), GaiaConstant::U32(b)) => {
440 let result = op(*a as i64, *b as i64);
441 (Some(GaiaConstant::U32(result as u32)), GaiaType::U32)
442 }
443 (GaiaConstant::U64(a), GaiaConstant::U64(b)) => {
444 let result = op(*a as i64, *b as i64);
445 (Some(GaiaConstant::U64(result as u64)), GaiaType::U64)
446 }
447 _ => (None, GaiaType::I32)
448 }
449}
450
451#[cfg(feature = "jvm-assembler")]
452fn evaluate_unary_op<F>(c: &GaiaConstant, op: F) -> Option<GaiaConstant>
454where F: Fn(i64) -> i64 {
455 match c {
456 GaiaConstant::I32(a) => {
457 let result = op(*a as i64);
458 Some(GaiaConstant::I32(result as i32))
459 }
460 GaiaConstant::I64(a) => {
461 let result = op(*a);
462 Some(GaiaConstant::I64(result))
463 }
464 GaiaConstant::U32(a) => {
465 let result = op(*a as i64);
466 Some(GaiaConstant::U32(result as u32))
467 }
468 GaiaConstant::U64(a) => {
469 let result = op(*a as i64);
470 Some(GaiaConstant::U64(result as u64))
471 }
472 GaiaConstant::Bool(a) => {
473 Some(GaiaConstant::Bool(!*a))
474 }
475 _ => None
476 }
477}
478
479#[cfg(feature = "jvm-assembler")]
480fn eliminate_dead_code(instructions: &[GaiaInstruction]) -> Vec<GaiaInstruction> {
482 let mut optimized = vec![];
483 let mut reachable = true;
484 let mut i = 0;
485
486 while i < instructions.len() {
487 match &instructions[i] {
488 GaiaInstruction::Core(CoreInstruction::Br(label)) => {
489 optimized.push(instructions[i].clone());
490 reachable = false;
492 i += 1;
493 }
494 GaiaInstruction::Core(CoreInstruction::BrTrue(label)) |
495 GaiaInstruction::Core(CoreInstruction::BrFalse(label)) => {
496 optimized.push(instructions[i].clone());
497 i += 1;
499 }
500 GaiaInstruction::Core(CoreInstruction::Ret) => {
501 optimized.push(instructions[i].clone());
502 reachable = false;
504 i += 1;
505 }
506 GaiaInstruction::Core(CoreInstruction::Label(name)) => {
507 optimized.push(instructions[i].clone());
509 reachable = true;
510 i += 1;
511 }
512 _ => {
513 if reachable {
514 optimized.push(instructions[i].clone());
515 }
516 i += 1;
517 }
518 }
519 }
520
521 optimized
522}
523
524#[cfg(feature = "jvm-assembler")]
525fn optimize_jvm_instructions(instructions: Vec<JvmInstruction>) -> Vec<JvmInstruction> {
527 let mut optimized = vec![];
528 let mut i = 0;
529
530 while i < instructions.len() {
531 match &instructions[i] {
533 JvmInstruction::Bipush { value } if *value >= -1 && *value <= 5 => {
535 match *value {
536 -1 => optimized.push(JvmInstruction::IconstM1),
537 0 => optimized.push(JvmInstruction::Iconst0),
538 1 => optimized.push(JvmInstruction::Iconst1),
539 2 => optimized.push(JvmInstruction::Iconst2),
540 3 => optimized.push(JvmInstruction::Iconst3),
541 4 => optimized.push(JvmInstruction::Iconst4),
542 5 => optimized.push(JvmInstruction::Iconst5),
543 _ => optimized.push(instructions[i].clone()),
544 }
545 i += 1;
546 continue;
547 }
548
549 JvmInstruction::Iload { index } if *index <= 3 => {
551 match *index {
552 0 => optimized.push(JvmInstruction::Iload0),
553 1 => optimized.push(JvmInstruction::Iload1),
554 2 => optimized.push(JvmInstruction::Iload2),
555 3 => optimized.push(JvmInstruction::Iload3),
556 _ => optimized.push(instructions[i].clone()),
557 }
558 i += 1;
559 continue;
560 }
561
562 JvmInstruction::Istore { index } if *index <= 3 => {
563 match *index {
564 0 => optimized.push(JvmInstruction::Istore0),
565 1 => optimized.push(JvmInstruction::Istore1),
566 2 => optimized.push(JvmInstruction::Istore2),
567 3 => optimized.push(JvmInstruction::Istore3),
568 _ => optimized.push(instructions[i].clone()),
569 }
570 i += 1;
571 continue;
572 }
573
574 JvmInstruction::Pop => {
576 if !optimized.is_empty() {
578 match optimized.last().unwrap() {
579 JvmInstruction::Iconst0 | JvmInstruction::Iconst1 | JvmInstruction::Iconst2 |
580 JvmInstruction::Iconst3 | JvmInstruction::Iconst4 | JvmInstruction::Iconst5 |
581 JvmInstruction::IconstM1 | JvmInstruction::AconstNull |
582 JvmInstruction::Fconst0 | JvmInstruction::Fconst1 | JvmInstruction::Fconst2 |
583 JvmInstruction::Dconst0 | JvmInstruction::Dconst1 | JvmInstruction::Lconst0 |
584 JvmInstruction::Lconst1 => {
585 optimized.pop();
587 i += 1;
588 continue;
589 }
590 _ => {}
591 }
592 }
593 optimized.push(instructions[i].clone());
594 i += 1;
595 }
596
597 _ => {
599 if !optimized.is_empty() && optimized.last().unwrap() == &instructions[i] {
600 i += 1;
602 continue;
603 }
604 optimized.push(instructions[i].clone());
605 i += 1;
606 }
607 }
608 }
609
610 optimized
611}
612
613#[cfg(feature = "jvm-assembler")]
614fn convert_gaia_instruction_to_jvm(instruction: &GaiaInstruction, ctx: &JvmContext) -> Result<Vec<JvmInstruction>> {
616 match instruction {
617 GaiaInstruction::Core(core) => {
618
619
620 match core {
621 CoreInstruction::PushConstant(constant) => match constant {
622 GaiaConstant::I8(value) => Ok(vec![JvmInstruction::Bipush { value: *value }]),
623 GaiaConstant::U8(value) => Ok(vec![JvmInstruction::Bipush { value: *value as i8 }]),
624 GaiaConstant::I16(value) => Ok(vec![JvmInstruction::Sipush { value: *value }]),
625 GaiaConstant::U16(value) => Ok(vec![JvmInstruction::Sipush { value: *value as i16 }]),
626 GaiaConstant::I32(value) => match *value {
627 0 => Ok(vec![JvmInstruction::Iconst0]),
628 1 => Ok(vec![JvmInstruction::Iconst1]),
629 2 => Ok(vec![JvmInstruction::Iconst2]),
630 3 => Ok(vec![JvmInstruction::Iconst3]),
631 4 => Ok(vec![JvmInstruction::Iconst4]),
632 5 => Ok(vec![JvmInstruction::Iconst5]),
633 -1 => Ok(vec![JvmInstruction::IconstM1]),
634 _ if *value >= -128 && *value <= 127 => Ok(vec![JvmInstruction::Bipush { value: *value as i8 }]),
635 _ if *value >= -32768 && *value <= 32767 => Ok(vec![JvmInstruction::Sipush { value: *value as i16 }]),
636 _ => Ok(vec![JvmInstruction::Ldc { symbol: value.to_string() }]),
637 },
638 GaiaConstant::U32(value) => Ok(vec![JvmInstruction::Ldc { symbol: value.to_string() }]),
639 GaiaConstant::I64(value) => Ok(vec![JvmInstruction::Ldc2W { symbol: value.to_string() }]),
640 GaiaConstant::U64(value) => Ok(vec![JvmInstruction::Ldc2W { symbol: value.to_string() }]),
641 GaiaConstant::F32(value) => match *value {
642 0.0 => Ok(vec![JvmInstruction::Fconst0]),
643 1.0 => Ok(vec![JvmInstruction::Fconst1]),
644 2.0 => Ok(vec![JvmInstruction::Fconst2]),
645 _ => Ok(vec![JvmInstruction::Ldc { symbol: value.to_string() }]),
646 },
647 GaiaConstant::F64(value) => match *value {
648 0.0 => Ok(vec![JvmInstruction::Dconst0]),
649 1.0 => Ok(vec![JvmInstruction::Dconst1]),
650 _ => Ok(vec![JvmInstruction::Ldc2W { symbol: value.to_string() }]),
651 },
652 GaiaConstant::String(value) => Ok(vec![JvmInstruction::Ldc { symbol: value.clone() }]),
653 GaiaConstant::Bool(value) => Ok(vec![if *value { JvmInstruction::Iconst1 } else { JvmInstruction::Iconst0 }]),
654 GaiaConstant::Null => Ok(vec![JvmInstruction::AconstNull]),
655 _ => Err(GaiaError::custom_error("Unsupported constant type for JVM")),
656 },
657 CoreInstruction::Load(gaia_type) => {
658 Err(GaiaError::custom_error(&format!("JVM indirect load not supported for type: {:?}", gaia_type)))
660 },
661 CoreInstruction::Store(gaia_type) => {
662 Err(GaiaError::custom_error(&format!("JVM indirect store not supported for type: {:?}", gaia_type)))
664 },
665 CoreInstruction::Add(ty) => Ok(vec![match ty {
666 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Iadd,
667 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Ladd,
668 GaiaType::F32 => JvmInstruction::Fadd,
669 GaiaType::F64 => JvmInstruction::Dadd,
670 _ => JvmInstruction::Iadd,
671 }]),
672 CoreInstruction::Sub(ty) => Ok(vec![match ty {
673 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Isub,
674 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lsub,
675 GaiaType::F32 => JvmInstruction::Fsub,
676 GaiaType::F64 => JvmInstruction::Dsub,
677 _ => JvmInstruction::Isub,
678 }]),
679 CoreInstruction::Mul(ty) => Ok(vec![match ty {
680 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Imul,
681 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lmul,
682 GaiaType::F32 => JvmInstruction::Fmul,
683 GaiaType::F64 => JvmInstruction::Dmul,
684 _ => JvmInstruction::Imul,
685 }]),
686 CoreInstruction::Div(ty) => Ok(vec![match ty {
687 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Idiv,
688 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Ldiv,
689 GaiaType::F32 => JvmInstruction::Fdiv,
690 GaiaType::F64 => JvmInstruction::Ddiv,
691 _ => JvmInstruction::Idiv,
692 }]),
693 CoreInstruction::Rem(ty) => Ok(vec![match ty {
694 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Irem,
695 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lrem,
696 GaiaType::F32 => JvmInstruction::Frem,
697 GaiaType::F64 => JvmInstruction::Drem,
698 _ => JvmInstruction::Irem,
699 }]),
700 CoreInstruction::Pop => Ok(vec![JvmInstruction::Pop]),
701 CoreInstruction::Ret => Ok(vec![JvmInstruction::Return]),
702 CoreInstruction::Br(label) => Ok(vec![JvmInstruction::Goto { target: label.clone() }]),
703 CoreInstruction::BrTrue(label) => Ok(vec![JvmInstruction::Ifne { target: label.clone() }]),
704 CoreInstruction::BrFalse(label) => Ok(vec![JvmInstruction::Ifeq { target: label.clone() }]),
705 CoreInstruction::Label(name) => Ok(vec![JvmInstruction::Label { name: name.clone() }]),
706 CoreInstruction::Call(name, arg_count) => {
707 let jvm_target = gaia_types::helpers::CompilationTarget {
708 build: gaia_types::helpers::Architecture::JVM,
709 host: gaia_types::helpers::AbiCompatible::JavaAssembly,
710 target: gaia_types::helpers::ApiCompatible::JvmRuntime(8),
711 };
712 let mapped = ctx.function_mapper.map_function(&jvm_target, name).unwrap_or(name);
713
714 let mut descriptor = "()V".to_string();
717
718 if name.starts_with("java/") || name.starts_with("java.lang/") {
720 let parts: Vec<&str> = name.split('.').collect();
722 if parts.len() >= 2 {
723 let class_name = parts[0..parts.len()-1].join("/");
724 let method_name = parts[parts.len()-1];
725
726 descriptor = match (class_name.as_str(), method_name, *arg_count) {
728 ("java/lang/System", "exit", 1) => "(I)V".to_string(),
729 ("java/lang/System", "currentTimeMillis", 0) => "()J".to_string(),
730 ("java/lang/System", "arraycopy", 5) => "(Ljava/lang/Object;ILjava/lang/Object;II)V".to_string(),
731 ("java/lang/String", "valueOf", 1) => "(I)Ljava/lang/String;".to_string(),
732 ("java/lang/Integer", "parseInt", 1) => "(Ljava/lang/String;)I".to_string(),
733 _ => format!("({})V", "I".repeat(*arg_count)),
734 };
735
736 Ok(vec![JvmInstruction::Invokestatic {
737 class_name,
738 method_name: method_name.to_string(),
739 descriptor,
740 }])
741 } else {
742 Ok(vec![JvmInstruction::Invokestatic {
743 class_name: "Main".to_string(),
744 method_name: mapped.to_string(),
745 descriptor,
746 }])
747 }
748 } else {
749 descriptor = format!("({})V", "I".repeat(*arg_count));
752
753 if *arg_count > 255 {
755 return Err(GaiaError::custom_error("Too many arguments for JVM method call"));
756 }
757
758 Ok(vec![JvmInstruction::Invokestatic {
759 class_name: "Main".to_string(),
760 method_name: mapped.to_string(),
761 descriptor,
762 }])
763 }
764 },
765 CoreInstruction::LoadLocal(index, ty) => {
766 if *index > 65535 {
768 return Err(GaiaError::custom_error("Local variable index out of range for JVM"));
769 }
770 Ok(vec![match ty {
771 GaiaType::I32
772 | GaiaType::U32
773 | GaiaType::Bool
774 | GaiaType::I8
775 | GaiaType::U8
776 | GaiaType::I16
777 | GaiaType::U16 => JvmInstruction::Iload { index: *index as u16 },
778 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lload { index: *index as u16 },
779 GaiaType::F32 => JvmInstruction::Fload { index: *index as u16 },
780 GaiaType::F64 => JvmInstruction::Dload { index: *index as u16 },
781 _ => JvmInstruction::Aload { index: *index as u16 },
782 }])
783 },
784 CoreInstruction::StoreLocal(index, ty) => {
785 if *index > 65535 {
787 return Err(GaiaError::custom_error("Local variable index out of range for JVM"));
788 }
789 Ok(vec![match ty {
790 GaiaType::I32
791 | GaiaType::U32
792 | GaiaType::Bool
793 | GaiaType::I8
794 | GaiaType::U8
795 | GaiaType::I16
796 | GaiaType::U16 => JvmInstruction::Istore { index: *index as u16 },
797 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lstore { index: *index as u16 },
798 GaiaType::F32 => JvmInstruction::Fstore { index: *index as u16 },
799 GaiaType::F64 => JvmInstruction::Dstore { index: *index as u16 },
800 _ => JvmInstruction::Astore { index: *index as u16 },
801 }])
802 },
803 CoreInstruction::LoadArg(index, ty) => {
804 if *index > 65535 {
806 return Err(GaiaError::custom_error("Argument index out of range for JVM"));
807 }
808 Ok(vec![match ty {
809 GaiaType::I32
810 | GaiaType::U32
811 | GaiaType::Bool
812 | GaiaType::I8
813 | GaiaType::U8
814 | GaiaType::I16
815 | GaiaType::U16 => JvmInstruction::Iload { index: *index as u16 },
816 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lload { index: *index as u16 },
817 GaiaType::F32 => JvmInstruction::Fload { index: *index as u16 },
818 GaiaType::F64 => JvmInstruction::Dload { index: *index as u16 },
819 _ => JvmInstruction::Aload { index: *index as u16 },
820 }])
821 },
822 CoreInstruction::StoreArg(index, ty) => {
823 if *index > 65535 {
825 return Err(GaiaError::custom_error("Argument index out of range for JVM"));
826 }
827 Ok(vec![match ty {
828 GaiaType::I32
829 | GaiaType::U32
830 | GaiaType::Bool
831 | GaiaType::I8
832 | GaiaType::U8
833 | GaiaType::I16
834 | GaiaType::U16 => JvmInstruction::Istore { index: *index as u16 },
835 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lstore { index: *index as u16 },
836 GaiaType::F32 => JvmInstruction::Fstore { index: *index as u16 },
837 GaiaType::F64 => JvmInstruction::Dstore { index: *index as u16 },
838 _ => JvmInstruction::Astore { index: *index as u16 },
839 }])
840 },
841 CoreInstruction::New(type_name) => Ok(vec![
842 JvmInstruction::New { class_name: type_name.replace('.', "/") },
843 JvmInstruction::Dup,
844 JvmInstruction::Invokespecial {
845 class_name: type_name.replace('.', "/"),
846 method_name: "<init>".to_string(),
847 descriptor: "()V".to_string(),
848 },
849 ]),
850 CoreInstruction::LoadField(type_name, field_name) => {
851 let descriptor = ctx
852 .field_types
853 .get(&(type_name.clone(), field_name.clone()))
854 .cloned()
855 .unwrap_or_else(|| "Ljava/lang/Object;".to_string());
856 Ok(vec![JvmInstruction::Getfield {
857 class_name: type_name.replace('.', "/"),
858 field_name: field_name.to_string(),
859 descriptor,
860 }])
861 }
862 CoreInstruction::StoreField(type_name, field_name) => {
863 let descriptor = ctx
864 .field_types
865 .get(&(type_name.clone(), field_name.clone()))
866 .cloned()
867 .unwrap_or_else(|| "Ljava/lang/Object;".to_string());
868 Ok(vec![JvmInstruction::Putfield {
869 class_name: type_name.replace('.', "/"),
870 field_name: field_name.to_string(),
871 descriptor,
872 }])
873 }
874 CoreInstruction::LoadElement(ty) => {
875 let mut instructions = vec![];
877
878 instructions.push(JvmInstruction::Dup);
880 instructions.push(JvmInstruction::Arraylength);
882 instructions.push(JvmInstruction::Swap);
884 instructions.push(JvmInstruction::Swap);
886 instructions.push(JvmInstruction::Lcmp);
888 instructions.push(JvmInstruction::Ifge { target: "array_index_out_of_bounds".to_string() });
890 instructions.push(match ty {
892 GaiaType::I32 | GaiaType::U32 => JvmInstruction::Iaload,
893 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Laload,
894 GaiaType::F32 => JvmInstruction::Faload,
895 GaiaType::F64 => JvmInstruction::Daload,
896 GaiaType::I8 | GaiaType::U8 | GaiaType::Bool => JvmInstruction::Baload,
897 GaiaType::I16 | GaiaType::U16 => JvmInstruction::Saload,
898 _ => JvmInstruction::Aaload,
899 });
900 instructions.push(JvmInstruction::Label { name: "array_index_out_of_bounds".to_string() });
902 instructions.push(JvmInstruction::New { class_name: "java/lang/ArrayIndexOutOfBoundsException".to_string() });
903 instructions.push(JvmInstruction::Dup);
904 instructions.push(JvmInstruction::Invokespecial { class_name: "java/lang/ArrayIndexOutOfBoundsException".to_string(), method_name: "<init>".to_string(), descriptor: "()V".to_string() });
905 instructions.push(JvmInstruction::Athrow);
906
907 Ok(instructions)
908 },
909 CoreInstruction::StoreElement(ty) => {
910 let mut instructions = vec![];
912
913 instructions.push(JvmInstruction::Dup2);
915 instructions.push(JvmInstruction::Arraylength);
917 instructions.push(JvmInstruction::Swap);
919 instructions.push(JvmInstruction::Swap);
921 instructions.push(JvmInstruction::Swap);
923 instructions.push(JvmInstruction::Lcmp);
925 instructions.push(JvmInstruction::Ifge { target: "array_index_out_of_bounds_store".to_string() });
927 instructions.push(match ty {
929 GaiaType::I32 | GaiaType::U32 => JvmInstruction::Iastore,
930 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lastore,
931 GaiaType::F32 => JvmInstruction::Fastore,
932 GaiaType::F64 => JvmInstruction::Dastore,
933 GaiaType::I8 | GaiaType::U8 | GaiaType::Bool => JvmInstruction::Bastore,
934 GaiaType::I16 | GaiaType::U16 => JvmInstruction::Sastore,
935 _ => JvmInstruction::Aastore,
936 });
937 instructions.push(JvmInstruction::Label { name: "array_index_out_of_bounds_store".to_string() });
939 instructions.push(JvmInstruction::New { class_name: "java/lang/ArrayIndexOutOfBoundsException".to_string() });
940 instructions.push(JvmInstruction::Dup);
941 instructions.push(JvmInstruction::Invokespecial { class_name: "java/lang/ArrayIndexOutOfBoundsException".to_string(), method_name: "<init>".to_string(), descriptor: "()V".to_string() });
942 instructions.push(JvmInstruction::Athrow);
943
944 Ok(instructions)
945 },
946 CoreInstruction::Cmp(condition, ty) => Ok(vec![match ty {
947 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Lcmp,
948 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lcmp,
949 GaiaType::F32 => JvmInstruction::Fcmpg,
950 GaiaType::F64 => JvmInstruction::Dcmpg,
951 _ => JvmInstruction::Lcmp,
952 }]),
953 CoreInstruction::Gep { base_type, indices } => Err(GaiaError::not_implemented("JVM GEP")),
954 CoreInstruction::NewArray(ty, is_length_on_stack) => {
955 let instructions = match ty {
957 GaiaType::I8 | GaiaType::U8 | GaiaType::Bool => vec![JvmInstruction::Newarray { type_code: 4 }], GaiaType::I16 | GaiaType::U16 => vec![JvmInstruction::Newarray { type_code: 5 }], GaiaType::I32 | GaiaType::U32 => vec![JvmInstruction::Newarray { type_code: 6 }], GaiaType::I64 | GaiaType::U64 => vec![JvmInstruction::Newarray { type_code: 7 }], GaiaType::F32 => vec![JvmInstruction::Newarray { type_code: 8 }], GaiaType::F64 => vec![JvmInstruction::Newarray { type_code: 9 }], GaiaType::Object | GaiaType::String => {
964 vec![JvmInstruction::Anewarray { class_name: ty.to_string().replace('.', "/") }]
965 },
966 _ => vec![JvmInstruction::Newarray { type_code: 6 }], };
968 Ok(instructions)
969 },
970 CoreInstruction::ArrayLength => Ok(vec![JvmInstruction::Arraylength]),
971 CoreInstruction::ArrayPush => {
972 Ok(vec![
975 JvmInstruction::Dup, JvmInstruction::Arraylength, JvmInstruction::Swap, JvmInstruction::Swap, JvmInstruction::Iastore, ])
981 },
982 CoreInstruction::Cast { from, to, kind } => {
983 let mut instructions = vec![];
985 match (from, to) {
986 (GaiaType::I8, GaiaType::I16) | (GaiaType::U8, GaiaType::I16) | (GaiaType::I8, GaiaType::I32) | (GaiaType::U8, GaiaType::I32) | (GaiaType::I16, GaiaType::I32) | (GaiaType::U16, GaiaType::I32) => {
988 }
990 (GaiaType::I8, GaiaType::I64) | (GaiaType::U8, GaiaType::I64) | (GaiaType::I16, GaiaType::I64) | (GaiaType::U16, GaiaType::I64) | (GaiaType::I32, GaiaType::I64) | (GaiaType::U32, GaiaType::I64) => {
991 instructions.push(JvmInstruction::I2l);
992 }
993 (GaiaType::I8, GaiaType::F32) | (GaiaType::U8, GaiaType::F32) | (GaiaType::I16, GaiaType::F32) | (GaiaType::U16, GaiaType::F32) | (GaiaType::I32, GaiaType::F32) | (GaiaType::U32, GaiaType::F32) => {
994 instructions.push(JvmInstruction::I2f);
995 }
996 (GaiaType::I8, GaiaType::F64) | (GaiaType::U8, GaiaType::F64) | (GaiaType::I16, GaiaType::F64) | (GaiaType::U16, GaiaType::F64) | (GaiaType::I32, GaiaType::F64) | (GaiaType::U32, GaiaType::F64) => {
997 instructions.push(JvmInstruction::I2d);
998 }
999 (GaiaType::I64, GaiaType::I32) => {
1000 instructions.push(JvmInstruction::L2i);
1001 }
1002 (GaiaType::I64, GaiaType::F32) => {
1003 instructions.push(JvmInstruction::L2f);
1004 }
1005 (GaiaType::I64, GaiaType::F64) => {
1006 instructions.push(JvmInstruction::L2d);
1007 }
1008 (GaiaType::F32, GaiaType::I32) => {
1009 instructions.push(JvmInstruction::F2i);
1010 }
1011 (GaiaType::F32, GaiaType::I64) => {
1012 instructions.push(JvmInstruction::F2l);
1013 }
1014 (GaiaType::F32, GaiaType::F64) => {
1015 instructions.push(JvmInstruction::F2d);
1016 }
1017 (GaiaType::F64, GaiaType::I32) => {
1018 instructions.push(JvmInstruction::D2i);
1019 }
1020 (GaiaType::F64, GaiaType::I64) => {
1021 instructions.push(JvmInstruction::D2l);
1022 }
1023 (GaiaType::F64, GaiaType::F32) => {
1024 instructions.push(JvmInstruction::D2f);
1025 }
1026 (_, GaiaType::Object) | (_, GaiaType::String) => {
1028 instructions.push(JvmInstruction::Checkcast { class_name: to.to_string().replace('.', "/") });
1029 }
1030 _ => {
1031 }
1033 }
1034 Ok(instructions)
1035 },
1036 CoreInstruction::And(ty) => Ok(vec![match ty {
1037 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Iand,
1038 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Land,
1039 _ => JvmInstruction::Iand,
1040 }]),
1041 CoreInstruction::Or(ty) => Ok(vec![match ty {
1042 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Ior,
1043 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lor,
1044 _ => JvmInstruction::Ior,
1045 }]),
1046 CoreInstruction::Xor(ty) => Ok(vec![match ty {
1047 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Ixor,
1048 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lxor,
1049 _ => JvmInstruction::Ixor,
1050 }]),
1051 CoreInstruction::Shl(ty) => Ok(vec![match ty {
1052 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Ishl,
1053 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lshl,
1054 _ => JvmInstruction::Ishl,
1055 }]),
1056 CoreInstruction::Shr(ty) => Ok(vec![match ty {
1057 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Ishr,
1058 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lshr,
1059 _ => JvmInstruction::Ishr,
1060 }]),
1061 CoreInstruction::Neg(ty) => Ok(vec![match ty {
1062 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Ineg,
1063 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lneg,
1064 GaiaType::F32 => JvmInstruction::Fneg,
1065 GaiaType::F64 => JvmInstruction::Dneg,
1066 _ => JvmInstruction::Ineg,
1067 }]),
1068 CoreInstruction::Not(ty) => Ok(vec![match ty {
1069 GaiaType::I32 | GaiaType::U32 | GaiaType::Bool | GaiaType::I8 | GaiaType::U8 | GaiaType::I16 | GaiaType::U16 => JvmInstruction::Ixor,
1070 GaiaType::I64 | GaiaType::U64 => JvmInstruction::Lxor,
1071 _ => JvmInstruction::Ixor,
1072 }]),
1073 CoreInstruction::CallIndirect(arg_count) => Err(GaiaError::not_implemented("JVM CallIndirect")),
1074 CoreInstruction::Alloca(ty, count) => {
1075 Ok(vec![])
1079 },
1080 CoreInstruction::Throw => Ok(vec![JvmInstruction::Athrow]),
1081
1082 _ => Ok(vec![]),
1083 }
1084 },
1085 _ => Ok(vec![]),
1086 }
1087}
1088
1089#[cfg(feature = "jvm-assembler")]
1090fn convert_gaia_type_to_jvm_descriptor(ty: &GaiaType) -> String {
1092 mapping::map_gaia_type_to_jvm_descriptor(ty)
1093}
1094
1095#[cfg(feature = "jvm-assembler")]
1096fn calculate_stack_and_locals(function: &GaiaFunction, _ctx: &JvmContext) -> Result<(u16, u16)> {
1098 let mut max_stack: i32 = 0;
1100 let mut current_stack: i32 = 0;
1101 let mut max_locals: u16 = 0;
1102
1103 for (i, param) in function.signature.params.iter().enumerate() {
1105 let size = match param {
1106 GaiaType::I64 | GaiaType::U64 | GaiaType::F64 => 2u16,
1107 _ => 1u16,
1108 };
1109 max_locals += size;
1110 }
1111
1112 for block in &function.blocks {
1114 for instruction in &block.instructions {
1115 match instruction {
1116 GaiaInstruction::Core(core) => match core {
1117 CoreInstruction::PushConstant(constant) => {
1118 match constant {
1119 GaiaConstant::I64(_) | GaiaConstant::U64(_) | GaiaConstant::F64(_) => {
1120 current_stack += 2;
1121 }
1122 _ => {
1123 current_stack += 1;
1124 }
1125 }
1126 if current_stack > max_stack {
1127 max_stack = current_stack;
1128 }
1129 }
1130 CoreInstruction::Add(ty) | CoreInstruction::Sub(ty) | CoreInstruction::Mul(ty) | CoreInstruction::Div(ty) | CoreInstruction::Rem(ty) => {
1131 match ty {
1132 GaiaType::I64 | GaiaType::U64 | GaiaType::F64 => {
1133 current_stack -= 1; }
1135 _ => {
1136 current_stack -= 1; }
1138 }
1139 }
1140 CoreInstruction::Pop => {
1141 current_stack -= 1;
1142 }
1143 CoreInstruction::Dup => {
1144 current_stack += 1;
1145 if current_stack > max_stack {
1146 max_stack = current_stack;
1147 }
1148 }
1149 CoreInstruction::LoadLocal(_, ty) | CoreInstruction::LoadArg(_, ty) => {
1150 match ty {
1151 GaiaType::I64 | GaiaType::U64 | GaiaType::F64 => {
1152 current_stack += 2;
1153 }
1154 _ => {
1155 current_stack += 1;
1156 }
1157 }
1158 if current_stack > max_stack {
1159 max_stack = current_stack;
1160 }
1161 }
1162 CoreInstruction::StoreLocal(index, ty) | CoreInstruction::StoreArg(index, ty) => {
1163 match ty {
1164 GaiaType::I64 | GaiaType::U64 | GaiaType::F64 => {
1165 current_stack -= 2;
1166 let local_index = *index as u16;
1167 if local_index + 1 > max_locals {
1168 max_locals = local_index + 2;
1169 }
1170 }
1171 _ => {
1172 current_stack -= 1;
1173 let local_index = *index as u16;
1174 if local_index > max_locals {
1175 max_locals = local_index + 1;
1176 }
1177 }
1178 }
1179 }
1180 CoreInstruction::New(_) => {
1181 current_stack += 1; if current_stack > max_stack {
1183 max_stack = current_stack;
1184 }
1185 }
1186 CoreInstruction::LoadField(_, _) => {
1187 current_stack += 1; if current_stack > max_stack {
1189 max_stack = current_stack;
1190 }
1191 }
1192 CoreInstruction::StoreField(_, _) => {
1193 current_stack -= 1; }
1195 CoreInstruction::LoadElement(ty) => {
1196 match ty {
1197 GaiaType::I64 | GaiaType::U64 | GaiaType::F64 => {
1198 current_stack += 1; }
1200 _ => {
1201 current_stack += 1; }
1203 }
1204 if current_stack > max_stack {
1205 max_stack = current_stack;
1206 }
1207 }
1208 CoreInstruction::StoreElement(ty) => {
1209 match ty {
1210 GaiaType::I64 | GaiaType::U64 | GaiaType::F64 => {
1211 current_stack -= 2; }
1213 _ => {
1214 current_stack -= 2; }
1216 }
1217 }
1218 CoreInstruction::Call(_, arg_count) => {
1219 current_stack -= *arg_count as i32;
1221 current_stack += 1;
1223 if current_stack > max_stack {
1224 max_stack = current_stack;
1225 }
1226 }
1227 CoreInstruction::NewArray(_, _) => {
1228 current_stack -= 1; current_stack += 1; }
1233 CoreInstruction::ArrayLength => {
1234 current_stack -= 1; current_stack += 1; }
1239 CoreInstruction::ArrayPush => {
1240 current_stack -= 2; }
1243 CoreInstruction::Throw => {
1244 current_stack -= 1;
1246 }
1247
1248 CoreInstruction::Br(_) | CoreInstruction::BrTrue(_) | CoreInstruction::BrFalse(_) | CoreInstruction::Label(_) => {
1249 }
1251 CoreInstruction::Ret => {
1252 current_stack = 0;
1254 }
1255 _ => {
1256 }
1258 },
1259 _ => {
1260 }
1262 }
1263 }
1264 }
1265
1266 if max_stack < 0 {
1268 max_stack = 0;
1269 }
1270
1271 max_stack = std::cmp::max(max_stack, 4);
1273 max_locals = std::cmp::max(max_locals, 4u16);
1274
1275 Ok((max_stack as u16, max_locals as u16))
1276}
1277
1278#[cfg(feature = "jvm-assembler")]
1279fn build_method_descriptor(params: &[GaiaType], return_type: &Option<GaiaType>) -> String {
1281 let mut descriptor = "(".to_string();
1282 for param in params {
1283 descriptor.push_str(&convert_gaia_type_to_jvm_descriptor(param));
1284 }
1285 descriptor.push(')');
1286 if let Some(ret) = return_type {
1287 descriptor.push_str(&convert_gaia_type_to_jvm_descriptor(ret));
1288 }
1289 else {
1290 descriptor.push('V');
1291 }
1292 descriptor
1293}