X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/icode_generation.nit b/src/syntax/icode_generation.nit index 43662f9..af61111 100644 --- a/src/syntax/icode_generation.nit +++ b/src/syntax/icode_generation.nit @@ -58,7 +58,9 @@ special ICodeBuilder if _variables.has_key(v) then return _variables[v] else - var reg = new_register(v.stype.as(not null)) + var t = v.stype + if t == null then t = visitor.type_object.as_nullable + var reg = new_register(t) _variables[v] = reg return reg end @@ -79,12 +81,16 @@ special ICodeBuilder # Register where a functionnal nit return must store its value readable writable var _return_value: nullable IRegister + # The method associated to the iroutine (if any) + readable var _method: nullable MMMethod + init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod) do - super(visitor.module, r, m) + super(visitor.module, r) _visitor = visitor _return_seq = r.body _return_value = r.result + _method = m end # Insert implicit super init calls @@ -115,17 +121,17 @@ special ICodeBuilder end var l = n.super_init_calls.length while i < l do - var p = n.super_init_calls[i] - if p == stop_prop then break + var sp = n.super_init_calls[i] + if sp == stop_prop then break var cargs = new Array[IRegister] - if p.signature.arity == 0 then + if sp.signature.arity == 0 then cargs.add(iroutine.params.first) else for va in iroutine.params do cargs.add(va) end end - stmt(new ICall(p, cargs)) + stmt(new ICall(sp, cargs)) i += 1 end end @@ -314,7 +320,7 @@ redef class AMethPropdef end redef class ASignature - fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: IndexedCollection[IRegister], closdecls: nullable IndexedCollection[IClosureDecl]) + fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: Sequence[IRegister], closdecls: nullable Sequence[IClosureDecl]) do for ap in n_params do var reg = v.variable(ap.variable) @@ -336,16 +342,23 @@ redef class AClosureDecl redef fun accept_icode_generation(vv) do var v = vv.icode_ctx - var iclos = variable.closure.signature.generate_empty_iclosuredef + var iclos = variable.closure.signature.generate_empty_iclosuredef(v) var old_seq = v.seq v.seq = iclos.body escapable.continue_seq = iclos.body escapable.continue_value = iclos.result + escapable.break_seq = v.return_seq + escapable.break_value = v.return_value n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null) if n_expr != null then v.generate_stmt(n_expr) v.iroutine.closure_decls[position].default = iclos + + # Add a final break in case of break block witout value + if variable.closure.is_break and v.return_value == null then + v.add_escape(v.return_seq.as(not null)) + end end v.seq = old_seq end @@ -540,16 +553,16 @@ redef class AInternMethPropdef end else if c == once "NativeArray".to_symbol then if n == once "object_id".to_symbol then - s = "TAG_Int(UNBOX_NativeArray(@@@))" + s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)" else if n == once "[]".to_symbol then - s = "UNBOX_NativeArray(@@@)[UNTAG_Int(@@@)]" + s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]" else if n == once "[]=".to_symbol then - s = "UNBOX_NativeArray(@@@)[UNTAG_Int(@@@)]=@@@;" + s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@" else if n == once "copy_to".to_symbol then var t = p[0] p[0] = p[1] p[1] = t - s = "(void)memcpy(UNBOX_NativeArray(@@@), UNBOX_NativeArray(@@@), UNTAG_Int(@@@)*sizeof(val_t));" + s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))" end else if c == once "NativeString".to_symbol then if n == once "object_id".to_symbol then @@ -569,7 +582,7 @@ redef class AInternMethPropdef s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));" end else if n == once "object_id".to_symbol then - s = "TAG_Int((bigint)@@@)" + s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)" else if n == once "sys".to_symbol then s = "(G_sys)" else if n == once "is_same_type".to_symbol then @@ -579,10 +592,10 @@ redef class AInternMethPropdef s = "exit(UNTAG_Int(@@@));" else if n == once "calloc_array".to_symbol then p[0] = p[1] - s = "BOX_NativeArray((val_t*)malloc((UNTAG_Int(@@@) * sizeof(val_t))))" + s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))" else if n == once "calloc_string".to_symbol then p[0] = p[1] - s = "BOX_NativeString((char*)malloc((UNTAG_Int(@@@) * sizeof(char))))" + s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))" end if s == null then v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.") @@ -630,7 +643,15 @@ end redef class ADoExpr redef fun generate_icode(v) do + var seq_old = v.seq + var seq = new ISeq + v.stmt(seq) + escapable.break_seq = seq + v.seq = seq + v.generate_stmt(n_block) + + v.seq = seq_old return null end end @@ -642,7 +663,7 @@ redef class AReturnExpr if ne != null then v.add_assignment(v.return_value.as(not null), v.generate_expr(ne)) end - v.stmt(new IEscape(v.return_seq.as(not null))) + v.add_escape(v.return_seq.as(not null)) return null end end @@ -654,7 +675,7 @@ redef class ABreakExpr if ne != null then v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne)) end - v.stmt(new IEscape(escapable.break_seq.as(not null))) + v.add_escape(escapable.break_seq.as(not null)) return null end end @@ -666,7 +687,7 @@ redef class AContinueExpr if ne != null then v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne)) end - v.stmt(new IEscape(escapable.continue_seq.as(not null))) + v.add_escape(escapable.continue_seq.as(not null)) return null end end @@ -723,61 +744,86 @@ redef class AWhileExpr # Process escape (condition is false) v.seq = iif.else_seq - v.stmt(new IEscape(iloop)) + v.add_escape(iloop) v.seq = seq_old return null end end -redef class AForExpr +redef class ALoopExpr redef fun generate_icode(v) do - var expr_type = n_expr.stype - - # Get iterator - var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol) - - var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null) - var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type) - - # Enter loop var seq_old = v.seq var iloop = new ILoop v.stmt(iloop) escapable.break_seq = iloop v.seq = iloop - # Condition evaluation - var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol)) - var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool) - var iif = new IIf(ireg_isok) + # Process inside + if n_block != null then + var seq = new ISeq + v.stmt(seq) + v.seq = seq + escapable.continue_seq = seq + v.generate_stmt(n_block) + end - # Process insite the loop (condition is true) - v.stmt(iif) - v.seq = iif.then_seq - escapable.continue_seq = iif.then_seq + v.seq = seq_old + return null + end +end + +redef class AForExpr + redef fun generate_icode(v) + do + var ne = n_expr + var expr_type = ne.stype + var tint = v.visitor.type_int + var meth # The method that call the closure + var args # The arguments of meth + + if ne isa ARangeExpr and expr_type == v.visitor.type_range(tint) then + # Shortcut. No Range[Int] object allocated. + # 'for x in [y..z] do' become 'y.enumerate_to(z) !each(x) do' + # 'for x in [y..z[ do' become 'y.enumerate_before(z) !each(x) do' + # And both methods may be inlined + args = [v.generate_expr(ne.n_expr), v.generate_expr(ne.n_expr2)] + if ne isa ACrangeExpr then + meth = v.visitor.get_method(tint, once "enumerate_to".to_symbol) + else + assert ne isa AOrangeExpr + meth = v.visitor.get_method(tint, once "enumerate_before".to_symbol) + end + else + # Standard way. + # 'for x in e do' become 'e.iterate !each(x) do' + # Some iterate methods may be inlined (eg. the Array one) + meth = v.visitor.get_method(expr_type, once "iterate".to_symbol) + args = [v.generate_expr(n_expr)] + end - # Automatic variable assignment - var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol)) - var va_stype = variable.stype.as(not null) - var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype) - var ireg_va = v.variable(variable) - v.add_assignment(ireg_va, ireg_item) + # Build closure + var iclos = meth.signature.closures.first.signature.generate_empty_iclosuredef(v) + var old_seq = v.seq + + var seq = new ISeq + v.stmt(seq) + v.seq = seq + escapable.break_seq = seq + escapable.break_value = null - # Body evaluation + v.seq = iclos.body + escapable.continue_seq = iclos.body + escapable.continue_value = null + v.stmt(new IMove(v.variable(variable), iclos.params.first)) v.generate_stmt(n_block) - # Exit contition (condition is false) - v.seq = iif.else_seq - v.stmt(new IEscape(iloop)) + # Call closure + v.seq = seq + v.add_call(meth, args, [iclos]) - # Next step - var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol)) - v.seq = iloop - v.stmt(new ICall(meth_next, [ireg_iter])) - - v.seq = seq_old + v.seq = old_seq return null end end @@ -790,6 +836,7 @@ redef class AAssertExpr v.stmt(iif) var seq_old = v.seq v.seq = iif.else_seq + v.generate_stmt(n_else) var id = n_id if id == null then v.add_abort("Assert failed") @@ -879,7 +926,7 @@ redef class AOrExpr v.stmt(iif) var seq_old = v.seq v.seq = iif.then_seq - v.add_assignment(reg, v.generate_expr(n_expr)) + v.add_assignment(reg, v.lit_true_reg) # Process right operand (in the else) v.seq = iif.else_seq @@ -901,7 +948,7 @@ redef class AAndExpr v.stmt(iif) var seq_old = v.seq v.seq = iif.else_seq - v.add_assignment(reg, v.generate_expr(n_expr)) + v.add_assignment(reg, v.lit_false_reg) # Process right operand (in the then) v.seq = iif.then_seq @@ -949,14 +996,14 @@ end redef class ATrueExpr redef fun generate_icode(v) do - return v.expr(new INative("TAG_Bool(true)", null), stype) + return v.lit_true_reg end end redef class AFalseExpr redef fun generate_icode(v) do - return v.expr(new INative("TAG_Bool(false)", null), stype) + return v.lit_false_reg end end @@ -1065,7 +1112,7 @@ end redef class ANullExpr redef fun generate_icode(v) do - return v.new_register(stype) + return v.lit_null_reg end end @@ -1129,7 +1176,7 @@ redef class ASuperExpr return null end else - var p = prop + p = prop var rtype = p.signature.return_type if rtype == null then v.stmt(new ISuper(p, args)) @@ -1184,10 +1231,29 @@ end redef class AAbsAbsSendExpr # Compile each argument and add them to the array - fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister]) - do - for a in arguments do - args.add(v.generate_expr(a)) + fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature) + do + var par_arity = signature.arity + var par_vararg = signature.vararg_rank + var raw_args = raw_arguments + var raw_arity = raw_args.length + var arg_idx = 0 + for par_idx in [0..par_arity[ do + var a: AExpr + var par_type = signature[par_idx] + if par_idx == par_vararg then + var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity) + for i in [0..(raw_arity-par_arity)] do + a = raw_args[arg_idx] + v.add_call_array_add(arr, v.generate_expr(a)) + arg_idx = arg_idx + 1 + end + args.add(arr) + else + a = raw_args[arg_idx] + args.add(v.generate_expr(a)) + arg_idx = arg_idx + 1 + end end end end @@ -1198,8 +1264,8 @@ redef class ASendExpr var recv = v.generate_expr(n_expr) var args = new Array[IRegister] args.add(recv) - generate_icode_for_arguments_in(v, args) var prop = prop + generate_icode_for_arguments_in(v, args, prop.signature.as(not null)) var r: nullable IRegister = null # The full result of the send (raw call + breaks) var r2: nullable IRegister # The raw result of the call @@ -1217,14 +1283,24 @@ redef class ASendExpr closcns = new Array[nullable IClosureDef] var cdarity = 0 if closure_defs != null then cdarity = closure_defs.length - for i in [0..cdarity[ do - closure_defs[i].escapable.break_seq = seq - closure_defs[i].escapable.break_value = r - var cn = closure_defs[i].generate_iclosuredef(v) - closcns.add(cn) - end - for i in [cdarity..prop_signature.closures.length[ do - closcns.add(null) + var closure_defs = closure_defs + for mmc in prop_signature.closures do + var found = false + var name = mmc.name + if closure_defs != null then + for cd in closure_defs do + if cd.n_id.to_symbol != name then continue + assert found == false + found = true + cd.escapable.break_seq = seq + cd.escapable.break_value = r + var cn = cd.generate_iclosuredef(v) + closcns.add(cn) + end + end + if not found then + closcns.add(null) + end end end @@ -1252,7 +1328,7 @@ redef class ASendReassignExpr if n_expr.stype.is_nullable then v.add_null_reciever_check(recv) var args = new Array[IRegister] args.add(recv) - generate_icode_for_arguments_in(v, args) + generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null)) var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null)) var e3 = v.generate_expr(n_value) @@ -1268,7 +1344,7 @@ redef class ANewExpr redef fun generate_icode(v) do var args = new Array[IRegister] - generate_icode_for_arguments_in(v, args) + generate_icode_for_arguments_in(v, args, prop.signature.as(not null)) return v.expr(new INew(stype, prop, args), stype) end end @@ -1331,6 +1407,11 @@ redef class AClosureDef v.generate_stmt(n_expr) + # Add a final break in case of break block witout value + if closure.is_break and escapable.break_value == null then + v.add_escape(escapable.break_seq.as(not null)) + end + v.seq = seq_old _iclosure_def = iclos return iclos @@ -1342,7 +1423,7 @@ redef class AClosureCallExpr do # Geneate arguments var args = new Array[IRegister] - generate_icode_for_arguments_in(v, args) + generate_icode_for_arguments_in(v, args, variable.closure.signature) # Prepare icall var closdecl = v.closurevariables[variable] @@ -1386,7 +1467,7 @@ redef class AClosureCallExpr v.add_assignment(r, r2) end v.seq = iif.else_seq - var r3 = closdecl_default.inline_in_seq(iif.else_seq, args) + var r3 = v.inline_routine(closdecl_default, args, null) if r != null then assert r3 != null v.add_assignment(r, r3)