1use crate::bytecode::codegen::CodegenCtx;
2use crate::bytecode::error::BytecodeError;
3use crate::bytecode::lambda::{self, LambdaTable};
4use crate::call_resolver::ClassCatalog;
5use crate::classfile::{
6 AnnotationElementMetadata, AnnotationElementValueMetadata, AnnotationMetadata, ClassFileWriter,
7};
8use crate::hir::*;
9use crate::ty::Ty;
10use rust_asm::constants::V21;
11use rust_asm::opcodes;
12
13const OBJECT_CLASS: &str = "java/lang/Object";
14const INIT_METHOD: &str = "<init>";
15const CLINIT_METHOD: &str = "<clinit>";
16
17pub struct GeneratedClass {
18 pub internal_name: String,
19 pub bytes: Vec<u8>,
20}
21
22pub fn gen_class(unit: &CompilationUnit) -> Result<Vec<u8>, BytecodeError> {
23 let catalog = ClassCatalog::platform();
24 gen_class_with_catalog(unit, &catalog)
25}
26
27pub fn gen_class_with_catalog(
28 unit: &CompilationUnit,
29 catalog: &ClassCatalog,
30) -> Result<Vec<u8>, BytecodeError> {
31 gen_class_with_source_file(unit, catalog, None)
32}
33
34pub fn gen_class_with_source_file(
35 unit: &CompilationUnit,
36 catalog: &ClassCatalog,
37 source_file: Option<&str>,
38) -> Result<Vec<u8>, BytecodeError> {
39 gen_classes_with_source_file(unit, catalog, source_file)?
40 .into_iter()
41 .next()
42 .map(|class| class.bytes)
43 .ok_or_else(|| BytecodeError::new("no type declarations"))
44}
45
46pub fn gen_classes_with_source_file(
47 unit: &CompilationUnit,
48 catalog: &ClassCatalog,
49 source_file: Option<&str>,
50) -> Result<Vec<GeneratedClass>, BytecodeError> {
51 if unit.type_decls.is_empty() {
52 return Err(BytecodeError::new("no type declarations"));
53 }
54
55 let mut classes = Vec::new();
56 for type_decl in &unit.type_decls {
57 let nest_members = nested_type_names(type_decl);
58 gen_type_decl_class(
59 type_decl,
60 catalog,
61 source_file,
62 None,
63 &nest_members,
64 type_decl.name.as_str(),
65 &mut classes,
66 )?;
67 }
68 Ok(classes)
69}
70
71fn gen_type_decl_class(
72 type_decl: &TypeDecl,
73 catalog: &ClassCatalog,
74 source_file: Option<&str>,
75 nest_host: Option<&str>,
76 nest_members: &[String],
77 root_nest_host: &str,
78 classes: &mut Vec<GeneratedClass>,
79) -> Result<(), BytecodeError> {
80 crate::bytecode::validation::validate_type_decl(type_decl, catalog)?;
81 let mut writer = ClassFileWriter::new();
82 if let Some(source_file) = source_file {
83 writer.visit_source_file(source_file);
84 }
85 if let Some(host) = nest_host {
86 writer.visit_nest_host(host);
87 } else {
88 for member in nest_members {
89 writer.visit_nest_member(member);
90 }
91 }
92 gen_type_decl(&mut writer, type_decl, catalog);
93 classes.push(GeneratedClass {
94 internal_name: type_decl.name.to_string(),
95 bytes: writer.to_bytes().map_err(BytecodeError::new)?,
96 });
97 for inner in &type_decl.inner_types {
98 gen_type_decl_class(
99 inner,
100 catalog,
101 source_file,
102 Some(root_nest_host),
103 &[],
104 root_nest_host,
105 classes,
106 )?;
107 }
108 Ok(())
109}
110
111fn nested_type_names(type_decl: &TypeDecl) -> Vec<String> {
112 let mut names = Vec::new();
113 collect_nested_type_names(type_decl, &mut names);
114 names
115}
116
117fn collect_nested_type_names(type_decl: &TypeDecl, names: &mut Vec<String>) {
118 for inner in &type_decl.inner_types {
119 names.push(inner.name.to_string());
120 collect_nested_type_names(inner, names);
121 }
122}
123
124fn gen_type_decl(writer: &mut ClassFileWriter, type_decl: &TypeDecl, catalog: &ClassCatalog) {
125 let access_flags = class_access_flags(type_decl);
126 let super_name = super_name(type_decl);
127 let interfaces = interface_names(type_decl);
128 let interface_refs: Vec<_> = interfaces.iter().map(String::as_str).collect();
129
130 writer.visit(
131 V21,
132 access_flags,
133 &type_decl.name,
134 Some(super_name.as_str()),
135 &interface_refs,
136 );
137 if let Some(signature) = &type_decl.generic_signature {
138 writer.visit_signature(signature);
139 }
140 for annotation in &type_decl.annotations {
141 writer.visit_runtime_invisible_annotation(annotation_metadata(annotation));
142 }
143 for component in &type_decl.record_components {
144 writer.visit_record_component(
145 component.name.as_str(),
146 &component.ty.erasure().descriptor(),
147 component.generic_signature.as_deref(),
148 );
149 }
150
151 gen_fields(writer, &type_decl.fields);
152 gen_static_initializer(writer, type_decl, catalog);
153 if needs_default_constructor(type_decl) {
154 gen_default_constructor(writer, type_decl, &super_name, catalog);
155 }
156
157 let mut counter = 0u32;
158 for method in &type_decl.methods {
159 let lambdas = lambda::emit_lambda_methods(
160 writer,
161 type_decl,
162 &super_name,
163 catalog,
164 method,
165 &mut counter,
166 );
167 gen_method(writer, type_decl, method, &super_name, catalog, &lambdas);
168 }
169}
170
171fn annotation_metadata(annotation: &AnnotationUse) -> AnnotationMetadata {
172 AnnotationMetadata {
173 descriptor: annotation.descriptor.clone(),
174 elements: annotation
175 .elements
176 .iter()
177 .map(|element| AnnotationElementMetadata {
178 name: element.name.to_string(),
179 value: match &element.value {
180 AnnotationValue::String(value) => {
181 AnnotationElementValueMetadata::String(value.to_string())
182 }
183 AnnotationValue::Int(value) => AnnotationElementValueMetadata::Int(*value),
184 AnnotationValue::Boolean(value) => {
185 AnnotationElementValueMetadata::Boolean(*value)
186 }
187 },
188 })
189 .collect(),
190 }
191}
192
193fn gen_fields(writer: &mut ClassFileWriter, fields: &[FieldDecl]) {
194 for field in fields {
195 let descriptor = field.ty.descriptor();
196 let mut fw = writer.visit_field(field.access_flags, &field.name, &descriptor);
197 if let Some(signature) = &field.generic_signature {
198 fw.visit_signature(signature);
199 }
200 fw.visit_end(writer);
201 }
202}
203
204fn gen_method(
205 writer: &mut ClassFileWriter,
206 type_decl: &TypeDecl,
207 method: &MethodDecl,
208 super_name: &str,
209 catalog: &ClassCatalog,
210 lambdas: &LambdaTable,
211) {
212 let descriptor = method.signature.descriptor();
213 let mut mw = writer.visit_method(method.access_flags, &method.name, &descriptor);
214 if let Some(signature) = &method.generic_signature {
215 mw.visit_signature(signature);
216 }
217 for exception in &method.throws {
218 mw.visit_exception(&exception.internal_name());
219 }
220
221 if matches!(type_decl.kind, TypeDeclKind::Enum) && method.name == "values" {
222 gen_enum_values_method(&mut mw, type_decl);
223 } else if matches!(type_decl.kind, TypeDeclKind::Enum) && method.name == "valueOf" {
224 gen_enum_value_of_method(&mut mw, type_decl);
225 } else if method_has_code(method)
226 && let Some(block) = &method.root_block
227 {
228 mw.visit_code();
229 let mut ctx = CodegenCtx::new(writer, type_decl.name, catalog);
230 ctx.set_super_name(ustr::Ustr::from(super_name));
231 ctx.set_fields(&type_decl.fields);
232 ctx.set_methods(&type_decl.methods);
233 ctx.set_anonymous_info(type_decl.anonymous.as_ref());
234 ctx.lambdas = lambdas.clone();
235 ctx.begin_method(method);
236 declare_method_locals(&mut mw, type_decl, method);
237 gen_constructor_prelude(&mut mw, &ctx, method);
238 if method.name == INIT_METHOD {
239 emit_instance_field_initializers(&mut mw, &mut ctx, &type_decl.fields);
240 }
241 crate::bytecode::method_gen::gen_method_body(&mut mw, &mut ctx, &method.body, block);
242 mw.visit_maxs(0, 0);
243 }
244
245 mw.visit_end(writer);
246}
247
248fn gen_static_initializer(
249 writer: &mut ClassFileWriter,
250 type_decl: &TypeDecl,
251 catalog: &ClassCatalog,
252) {
253 if !has_static_field_initializers(&type_decl.fields)
254 && !matches!(type_decl.kind, TypeDeclKind::Enum)
255 {
256 return;
257 }
258
259 let mut mw = writer.visit_method(crate::classfile::ACC_STATIC, CLINIT_METHOD, "()V");
260 mw.visit_code();
261 let mut ctx = CodegenCtx::new(writer, type_decl.name, catalog);
262 ctx.set_fields(&type_decl.fields);
263 ctx.set_methods(&type_decl.methods);
264 ctx.set_anonymous_info(type_decl.anonymous.as_ref());
265 emit_static_field_initializers(&mut mw, &mut ctx, &type_decl.fields);
266 if matches!(type_decl.kind, TypeDeclKind::Enum) {
267 emit_enum_values_initializer(&mut mw, type_decl);
268 }
269 mw.visit_insn(opcodes::RETURN);
270 mw.visit_maxs(0, 0);
271 mw.visit_end(writer);
272}
273
274fn gen_enum_values_method(mw: &mut crate::classfile::MethodWriter, type_decl: &TypeDecl) {
275 mw.visit_code();
276 let array_descriptor = enum_array_descriptor(type_decl);
277 mw.visit_field_insn(
278 opcodes::GETSTATIC,
279 type_decl.name.as_str(),
280 "$VALUES",
281 &array_descriptor,
282 );
283 mw.visit_method_insn(
284 opcodes::INVOKEVIRTUAL,
285 &array_descriptor,
286 "clone",
287 "()Ljava/lang/Object;",
288 false,
289 );
290 mw.visit_type_insn(opcodes::CHECKCAST, &array_descriptor);
291 mw.visit_insn(opcodes::ARETURN);
292 mw.visit_maxs(0, 0);
293}
294
295fn gen_enum_value_of_method(mw: &mut crate::classfile::MethodWriter, type_decl: &TypeDecl) {
296 mw.visit_code();
297 mw.visit_ldc_insn_type(type_decl.name.as_str());
298 mw.visit_var_insn(opcodes::ALOAD, 0);
299 mw.visit_method_insn(
300 opcodes::INVOKESTATIC,
301 "java/lang/Enum",
302 "valueOf",
303 "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;",
304 false,
305 );
306 mw.visit_type_insn(opcodes::CHECKCAST, type_decl.name.as_str());
307 mw.visit_insn(opcodes::ARETURN);
308 mw.visit_maxs(0, 0);
309}
310
311fn emit_enum_values_initializer(mw: &mut crate::classfile::MethodWriter, type_decl: &TypeDecl) {
312 let constants = enum_constant_fields(type_decl);
313 mw.visit_ldc_insn_int(constants.len() as i32);
314 mw.visit_type_insn(opcodes::ANEWARRAY, type_decl.name.as_str());
315 for (index, field) in constants.iter().enumerate() {
316 mw.visit_insn(opcodes::DUP);
317 mw.visit_ldc_insn_int(index as i32);
318 mw.visit_field_insn(
319 opcodes::GETSTATIC,
320 type_decl.name.as_str(),
321 field.name.as_str(),
322 &field.ty.descriptor(),
323 );
324 mw.visit_insn(opcodes::AASTORE);
325 }
326 mw.visit_field_insn(
327 opcodes::PUTSTATIC,
328 type_decl.name.as_str(),
329 "$VALUES",
330 &enum_array_descriptor(type_decl),
331 );
332}
333
334fn enum_constant_fields(type_decl: &TypeDecl) -> Vec<&FieldDecl> {
335 type_decl
336 .fields
337 .iter()
338 .filter(|field| field.access_flags & crate::classfile::ACC_ENUM != 0)
339 .collect()
340}
341
342fn enum_array_descriptor(type_decl: &TypeDecl) -> String {
343 format!("[L{};", type_decl.name)
344}
345
346fn declare_method_locals(
347 mw: &mut crate::classfile::MethodWriter,
348 type_decl: &TypeDecl,
349 method: &MethodDecl,
350) {
351 let mut slot = 0;
352 if method.access_flags & crate::classfile::ACC_STATIC == 0 {
353 mw.visit_local_variable("this", &Ty::Class(type_decl.name).descriptor(), slot);
354 slot += 1;
355 }
356
357 for param in &method.params {
358 mw.visit_local_variable(param.name.as_str(), ¶m.ty.erasure().descriptor(), slot);
359 slot += param.ty.size() as u16;
360 }
361}
362
363fn gen_constructor_prelude(
364 mw: &mut crate::classfile::MethodWriter,
365 ctx: &CodegenCtx,
366 method: &MethodDecl,
367) {
368 if method.name != INIT_METHOD {
369 return;
370 }
371
372 if let Some(call) = &method.constructor_call {
373 mw.visit_var_insn(opcodes::ALOAD, 0);
374 let mut slot = 1u16;
375 for (index, param) in method.params.iter().enumerate() {
376 if index >= call.arg_offset && index < call.arg_offset + call.params.len() {
377 mw.visit_var_insn(crate::bytecode::local_var::load_opcode(¶m.ty), slot);
378 }
379 slot += param.ty.size() as u16;
380 }
381 let descriptor = format!(
382 "({})V",
383 call.params
384 .iter()
385 .map(|ty| ty.erasure().descriptor())
386 .collect::<String>()
387 );
388 mw.visit_method_insn(
389 opcodes::INVOKESPECIAL,
390 &call.owner.internal_name(),
391 INIT_METHOD,
392 &descriptor,
393 false,
394 );
395 if let Some(outer_this) = &ctx.outer_this {
396 mw.visit_var_insn(opcodes::ALOAD, 0);
397 mw.visit_var_insn(opcodes::ALOAD, 1);
398 mw.visit_field_insn(
399 opcodes::PUTFIELD,
400 ctx.class_name.as_str(),
401 outer_this.field_name.as_str(),
402 &outer_this.ty.descriptor(),
403 );
404 }
405 return;
406 }
407
408 mw.visit_var_insn(opcodes::ALOAD, 0);
409 mw.visit_method_insn(
410 opcodes::INVOKESPECIAL,
411 ctx.super_name.as_str(),
412 INIT_METHOD,
413 "()V",
414 false,
415 );
416}
417
418fn method_has_code(method: &MethodDecl) -> bool {
419 method.access_flags & (crate::classfile::ACC_ABSTRACT | crate::classfile::ACC_NATIVE) == 0
420}
421
422fn class_access_flags(type_decl: &TypeDecl) -> u16 {
423 if matches!(
424 type_decl.kind,
425 TypeDeclKind::Class | TypeDeclKind::Record | TypeDeclKind::Enum
426 ) {
427 type_decl.access_flags | crate::classfile::ACC_SUPER
428 } else {
429 type_decl.access_flags
430 }
431}
432
433fn super_name(type_decl: &TypeDecl) -> String {
434 type_decl
435 .super_class
436 .as_ref()
437 .map(|ty| ty.internal_name())
438 .unwrap_or_else(|| OBJECT_CLASS.to_string())
439}
440
441fn interface_names(type_decl: &TypeDecl) -> Vec<String> {
442 type_decl
443 .interfaces
444 .iter()
445 .map(|ty| ty.internal_name())
446 .collect()
447}
448
449fn needs_default_constructor(type_decl: &TypeDecl) -> bool {
450 matches!(type_decl.kind, TypeDeclKind::Class)
451 && !type_decl
452 .methods
453 .iter()
454 .any(|method| method.name == INIT_METHOD)
455}
456
457fn has_static_field_initializers(fields: &[FieldDecl]) -> bool {
458 fields.iter().any(|field| {
459 field.access_flags & crate::classfile::ACC_STATIC != 0 && field.initializer.is_some()
460 })
461}
462
463fn gen_default_constructor(
464 writer: &mut ClassFileWriter,
465 type_decl: &TypeDecl,
466 super_name: &str,
467 catalog: &ClassCatalog,
468) {
469 let mut mw = writer.visit_method(crate::classfile::ACC_PUBLIC, INIT_METHOD, "()V");
470 mw.visit_code();
471 let mut ctx = CodegenCtx::new(writer, type_decl.name, catalog);
472 ctx.set_super_name(ustr::Ustr::from(super_name));
473 ctx.set_fields(&type_decl.fields);
474 ctx.set_methods(&type_decl.methods);
475 ctx.set_anonymous_info(type_decl.anonymous.as_ref());
476 mw.visit_var_insn(opcodes::ALOAD, 0);
477 mw.visit_method_insn(
478 opcodes::INVOKESPECIAL,
479 super_name,
480 INIT_METHOD,
481 "()V",
482 false,
483 );
484 emit_instance_field_initializers(&mut mw, &mut ctx, &type_decl.fields);
485 mw.visit_insn(opcodes::RETURN);
486 mw.visit_maxs(0, 0);
487 mw.visit_end(writer);
488}
489
490fn emit_instance_field_initializers(
491 mw: &mut crate::classfile::MethodWriter,
492 ctx: &mut CodegenCtx,
493 fields: &[FieldDecl],
494) {
495 for field in fields {
496 if field.access_flags & crate::classfile::ACC_STATIC != 0 {
497 continue;
498 }
499 let Some(initializer) = field.initializer else {
500 continue;
501 };
502
503 mw.visit_var_insn(opcodes::ALOAD, 0);
504 crate::bytecode::expr_gen::gen_expr(mw, ctx, &field.body, initializer);
505 let value_ty = crate::bytecode::expr_gen::expr_ty(ctx, &field.body, initializer);
506 crate::bytecode::expr_gen::coerce(mw, &value_ty, &field.ty);
507 mw.visit_field_insn(
508 opcodes::PUTFIELD,
509 ctx.class_name.as_str(),
510 field.name.as_str(),
511 &field.ty.descriptor(),
512 );
513 }
514}
515
516fn emit_static_field_initializers(
517 mw: &mut crate::classfile::MethodWriter,
518 ctx: &mut CodegenCtx,
519 fields: &[FieldDecl],
520) {
521 for field in fields {
522 if field.access_flags & crate::classfile::ACC_STATIC == 0 {
523 continue;
524 }
525 let Some(initializer) = field.initializer else {
526 continue;
527 };
528
529 crate::bytecode::expr_gen::gen_expr(mw, ctx, &field.body, initializer);
530 let value_ty = crate::bytecode::expr_gen::expr_ty(ctx, &field.body, initializer);
531 crate::bytecode::expr_gen::coerce(mw, &value_ty, &field.ty);
532 mw.visit_field_insn(
533 opcodes::PUTSTATIC,
534 ctx.class_name.as_str(),
535 field.name.as_str(),
536 &field.ty.descriptor(),
537 );
538 }
539}