Skip to main content

rusty_javac/bytecode/
expr_gen.rs

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