Skip to main content

rusty_javac/bytecode/expr_gen/
mod.rs

1mod arrays;
2mod assign;
3pub(crate) mod branch;
4mod calls;
5mod convert;
6mod literals;
7mod ops;
8pub(crate) mod switch;
9mod types;
10mod values;
11
12use crate::bytecode::codegen::CodegenCtx;
13use crate::classfile::MethodWriter;
14use crate::hir::*;
15use crate::ty::Ty;
16use rust_asm::opcodes;
17
18pub(crate) use arrays::array_load_opcode;
19pub(crate) use convert::{cast, coerce, pop_ty, push_default_value};
20pub(crate) use types::expr_ty;
21
22pub fn gen_expr(mw: &mut MethodWriter, ctx: &mut CodegenCtx, body: &Body, expr_id: ExprId) {
23    match &body.exprs[expr_id] {
24        Expr::IntLiteral(value) => literals::emit_int(mw, *value),
25        Expr::LongLiteral(value) => literals::emit_long(mw, *value),
26        Expr::FloatLiteral(value) => literals::emit_float(mw, *value),
27        Expr::DoubleLiteral(value) => literals::emit_double(mw, *value),
28        Expr::BoolLiteral(value) => literals::emit_bool(mw, *value),
29        Expr::NullLiteral => mw.visit_insn(opcodes::ACONST_NULL),
30        Expr::StringLiteral(value) => mw.visit_ldc_insn_string(value),
31        Expr::CharLiteral(value) => literals::emit_int(mw, *value as i64),
32        Expr::This | Expr::Super => mw.visit_var_insn(opcodes::ALOAD, 0),
33        Expr::Ident(name) => values::emit_name(mw, ctx, *name),
34        Expr::ClassName(_) => push_default_value(mw, &Ty::object()),
35        Expr::FieldAccess { target, field } => {
36            if !calls::emit_field_access(mw, ctx, body, *target, *field) {
37                discard_expr(mw, ctx, body, *target);
38                push_default_value(mw, &expr_ty(ctx, body, expr_id));
39            }
40        }
41        Expr::MethodCall {
42            target,
43            method,
44            args,
45        } => {
46            if !calls::emit_method_call(mw, ctx, body, *target, *method, args) {
47                if let Some(target) = target {
48                    discard_expr(mw, ctx, body, *target);
49                }
50                for arg in args {
51                    discard_expr(mw, ctx, body, *arg);
52                }
53                push_default_value(mw, &expr_ty(ctx, body, expr_id));
54            }
55        }
56        Expr::Binary { op, left, right } => {
57            ops::emit_binary(mw, ctx, body, op.clone(), *left, *right);
58        }
59        Expr::Switch {
60            selector, cases, ..
61        } => switch::emit_switch_expr(mw, ctx, body, *selector, cases),
62        Expr::Ternary {
63            condition,
64            then_expr,
65            else_expr,
66        } => emit_ternary(mw, ctx, body, expr_id, *condition, *then_expr, *else_expr),
67        Expr::Unary { op, operand } => ops::emit_unary(mw, ctx, body, op, *operand),
68        Expr::NewObject {
69            class,
70            args,
71            anonymous,
72        } => {
73            let owner = anonymous
74                .as_ref()
75                .map(|info| info.class_name.to_string())
76                .unwrap_or_else(|| class.internal_name());
77            let arg_types = args
78                .iter()
79                .map(|arg| expr_ty(ctx, body, *arg))
80                .collect::<Vec<_>>();
81            let constructor_params = anonymous
82                .as_ref()
83                .map(|info| info.constructor_params.clone())
84                .or_else(|| {
85                    ctx.catalog
86                        .resolve_constructor(&class.internal_name(), &arg_types)
87                        .map(|ctor| ctor.params)
88                })
89                .unwrap_or_else(|| arg_types.clone());
90            mw.visit_type_insn(opcodes::NEW, &owner);
91            mw.visit_insn(opcodes::DUP);
92            let mut descriptor = String::from("(");
93            if anonymous
94                .as_ref()
95                .is_some_and(|info| info.captures_enclosing_this)
96            {
97                mw.visit_var_insn(opcodes::ALOAD, 0);
98                descriptor.push_str(&Ty::Class(ctx.class_name).descriptor());
99            }
100            for (index, arg) in args.iter().enumerate() {
101                gen_expr(mw, ctx, body, *arg);
102                let arg_ty = &arg_types[index];
103                let param_ty = constructor_params
104                    .get(index)
105                    .cloned()
106                    .unwrap_or_else(|| arg_ty.clone());
107                coerce(mw, arg_ty, &param_ty);
108                descriptor.push_str(&param_ty.erasure().descriptor());
109            }
110            descriptor.push_str(")V");
111            mw.visit_method_insn(opcodes::INVOKESPECIAL, &owner, "<init>", &descriptor, false);
112        }
113        Expr::Parens(inner) => gen_expr(mw, ctx, body, *inner),
114        Expr::Cast { ty, expr } => {
115            gen_expr(mw, ctx, body, *expr);
116            cast(mw, &expr_ty(ctx, body, *expr), ty);
117        }
118        Expr::NewArray {
119            element_type,
120            dimensions,
121            initializer,
122        } => arrays::emit_new_array(
123            mw,
124            ctx,
125            body,
126            element_type,
127            dimensions,
128            initializer.as_ref(),
129        ),
130        Expr::ArrayAccess { array, index } => {
131            arrays::emit_array_access(mw, ctx, body, *array, *index)
132        }
133        Expr::Assign { target, op, value } => {
134            assign::emit_assign(mw, ctx, body, *target, op, *value)
135        }
136        Expr::PostInc(target) => assign::emit_post_inc_dec(mw, ctx, body, *target, 1),
137        Expr::PostDec(target) => assign::emit_post_inc_dec(mw, ctx, body, *target, -1),
138        Expr::Instanceof { expr, ty, .. } => {
139            gen_expr(mw, ctx, body, *expr);
140            mw.visit_type_insn(opcodes::INSTANCEOF, &ty.internal_name());
141        }
142        Expr::Lambda { .. } => crate::bytecode::lambda::emit_invokedynamic(mw, ctx, expr_id),
143        _ => push_default_value(mw, &expr_ty(ctx, body, expr_id)),
144    }
145}
146
147pub(crate) fn discard_expr(
148    mw: &mut MethodWriter,
149    ctx: &mut CodegenCtx,
150    body: &Body,
151    expr_id: ExprId,
152) {
153    gen_expr(mw, ctx, body, expr_id);
154    pop_ty(mw, &expr_ty(ctx, body, expr_id));
155}
156
157pub(crate) fn gen_expr_for_effect(
158    mw: &mut MethodWriter,
159    ctx: &mut CodegenCtx,
160    body: &Body,
161    expr_id: ExprId,
162) {
163    match &body.exprs[expr_id] {
164        Expr::Assign { target, op, value }
165            if assign::emit_assign_for_effect(mw, ctx, body, *target, op, *value) => {}
166        Expr::PostInc(target)
167        | Expr::Unary {
168            op: UnaryOp::PreInc,
169            operand: target,
170        } if assign::emit_inc_dec_for_effect(mw, ctx, body, *target, 1) => {}
171        Expr::PostDec(target)
172        | Expr::Unary {
173            op: UnaryOp::PreDec,
174            operand: target,
175        } if assign::emit_inc_dec_for_effect(mw, ctx, body, *target, -1) => {}
176        _ => discard_expr(mw, ctx, body, expr_id),
177    }
178}
179
180pub(crate) fn is_string(ty: &Ty) -> bool {
181    ty.is_string()
182}
183
184fn emit_ternary(
185    mw: &mut MethodWriter,
186    ctx: &mut CodegenCtx,
187    body: &Body,
188    expr_id: ExprId,
189    condition: ExprId,
190    then_expr: ExprId,
191    else_expr: ExprId,
192) {
193    let else_label = crate::classfile::Label::new();
194    let end_label = crate::classfile::Label::new();
195    let result_ty = expr_ty(ctx, body, expr_id);
196
197    gen_expr(mw, ctx, body, condition);
198    mw.visit_jump_insn(opcodes::IFEQ, else_label);
199    gen_expr(mw, ctx, body, then_expr);
200    coerce(mw, &expr_ty(ctx, body, then_expr), &result_ty);
201    mw.visit_jump_insn(opcodes::GOTO, end_label);
202    mw.visit_label(else_label);
203    gen_expr(mw, ctx, body, else_expr);
204    coerce(mw, &expr_ty(ctx, body, else_expr), &result_ty);
205    mw.visit_label(end_label);
206}