gitignore nit* in bin/
[nit.git] / src / global_compiler.nit
index c6e61b1..5865869 100644 (file)
@@ -133,9 +133,19 @@ redef class ModelBuilder
                end
                self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2)
 
+               var time1 = get_time
+               self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2)
+               write_and_make(compiler)
+       end
+
+       protected fun write_and_make(compiler: GlobalCompiler)
+       do
+               var mainmodule = compiler.mainmodule
+
                # Generate the .h and .c files
                # A single C file regroups many compiled rumtime functions
                # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
+               var time0 = get_time
 
                var outname = self.toolcontext.opt_output.value
                if outname == null then
@@ -206,7 +216,7 @@ redef class ModelBuilder
                        ofiles.add(o)
                end
                # Link edition
-               makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) $(LDLIBS) -o {outname} {ofiles.join(" ")}\n\n")
+               makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n")
                # Clean
                makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
                makefile.close
@@ -239,7 +249,7 @@ redef class ModelBuilder
 end
 
 # Singleton that store the knowledge about the compilation process
-private class GlobalCompiler
+class GlobalCompiler
        # The main module of the program
        var mainmodule: MModule
 
@@ -270,11 +280,11 @@ private class GlobalCompiler
        var live_primitive_types: Array[MClassType]
 
        # runtime_functions that need to be compiled
-       private var todos: List[RuntimeFunction] = new List[RuntimeFunction]
+       private var todos: List[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
 
        # runtime_functions already seen (todo or done)
-       private var seen: HashSet[RuntimeFunction] = new HashSet[RuntimeFunction]
-       fun todo(m: RuntimeFunction)
+       private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
+       fun todo(m: AbstractRuntimeFunction)
        do
                if seen.has(m) then return
                todos.add(m)
@@ -285,7 +295,7 @@ private class GlobalCompiler
        #
        # FIXME: should not be a vistor but just somewhere to store lines
        # FIXME: should not have a global .h since it does not help recompilations
-       var header: nullable GlobalCompilerVisitor = null
+       var header: nullable GlobalCompilerVisitor writable = null
 
        # The list of all associated visitors
        # Used to generate .c files
@@ -307,7 +317,7 @@ private class GlobalCompiler
        end
 
        # Cache for classid (computed by declare_runtimeclass)
-       private var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
+       protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
 
        # Declare C structures and identifiers for a runtime class
        fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
@@ -322,6 +332,11 @@ private class GlobalCompiler
                v.add_decl("struct {mtype.c_name} \{")
                v.add_decl("int classid; /* must be {idname} */")
 
+               if mtype.mclass.name == "NativeArray" then
+                       # NativeArrays are just a instance header followed by an array of values
+                       v.add_decl("{mtype.arguments.first.ctype} values[1];")
+               end
+
                if mtype.ctype != "val*" then
                        # Is the Nit type is native then the struct is a box with two fields:
                        # * the `classid` to be polymorph
@@ -349,12 +364,26 @@ private class GlobalCompiler
                assert mtype.ctype == "val*"
                var v = new GlobalCompilerVisitor(self)
 
-               self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void);")
+               var is_native_array = mtype.mclass.name == "NativeArray"
+
+               var sig
+               if is_native_array then
+                       sig = "int length"
+               else
+                       sig = "void"
+               end
+
+               self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig});")
                v.add_decl("/* allocate {mtype} */")
-               v.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void) \{")
+               v.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig}) \{")
                var res = v.new_var(mtype)
                res.is_exact = true
-               v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+               if is_native_array then
+                       var mtype_elt = mtype.arguments.first
+                       v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
+               else
+                       v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+               end
                v.add("{res}->classid = {self.classid(mtype)};")
 
                for cd in mtype.collect_mclassdefs(self.mainmodule)
@@ -506,8 +535,8 @@ redef class MClassType
                else if mclass.name == "NativeString" then
                        return "char*"
                else if mclass.name == "NativeArray" then
-                       assert self isa MGenericType
-                       return "{self.arguments.first.ctype}*"
+                       #return "{self.arguments.first.ctype}*"
+                       return "val*"
                else if mclass.kind == extern_kind then
                        return "void*"
                else
@@ -530,6 +559,17 @@ redef class MGenericType
        end
 end
 
+redef class MParameterType
+       redef fun c_name
+       do
+               var res = self.c_name_cache
+               if res != null then return res
+               res = "FT{self.rank}"
+               self.c_name_cache = res
+               return res
+       end
+end
+
 redef class MNullableType
        redef fun c_name
        do
@@ -543,12 +583,25 @@ end
 
 # A C function associated to a Nit method
 # Because of customization, a given Nit method can be compiler more that once
-private abstract class RuntimeFunction
+abstract class AbstractRuntimeFunction
        # The associated Nit method
        var mmethoddef: MMethodDef
 
        # The mangled c name of the runtime_function
-       fun c_name: String is abstract
+       # Subclasses should redefine `build_c_name` instead
+       fun c_name: String
+       do
+               var res = self.c_name_cache
+               if res != null then return res
+               res = self.build_c_name
+               self.c_name_cache = res
+               return res
+       end
+
+       # Non cached version of `c_name`
+       protected fun build_c_name: String is abstract
+
+       private var c_name_cache: nullable String = null
 
        # Implements a call of the runtime_function
        # May inline the body or generate a C function call
@@ -561,7 +614,7 @@ end
 
 # A runtime function customized on a specific monomrph receiver type
 private class CustomizedRuntimeFunction
-       super RuntimeFunction
+       super AbstractRuntimeFunction
 
        # The considered reciever
        # (usually is a live type but no strong guarantee)
@@ -573,8 +626,7 @@ private class CustomizedRuntimeFunction
                self.recv = recv
        end
 
-       # The mangled c name of the runtime_function
-       redef fun c_name: String
+       redef fun build_c_name: String
        do
                var res = self.c_name_cache
                if res != null then return res
@@ -587,8 +639,6 @@ private class CustomizedRuntimeFunction
                return res
        end
 
-       private var c_name_cache: nullable String = null
-
        redef fun ==(o)
        # used in the compiler worklist
        do
@@ -646,8 +696,8 @@ private class CustomizedRuntimeFunction
                        sig.append("void ")
                end
                sig.append(self.c_name)
-               sig.append("({recv.ctype} self")
-               comment.append("(self: {recv}")
+               sig.append("({recv.ctype} {selfvar}")
+               comment.append("(self: {selfvar}")
                arguments.add(selfvar)
                for i in [0..mmethoddef.msignature.arity[ do
                        var mtype = mmethoddef.msignature.mparameters[i].mtype
@@ -688,7 +738,7 @@ private class CustomizedRuntimeFunction
        do
                var ret = self.mmethoddef.msignature.return_mtype
                if self.mmethoddef.mproperty.is_new then
-                       ret = arguments.first.mtype
+                       ret = recv
                end
                if ret != null then
                        ret = v.resolve_for(ret, arguments.first)
@@ -725,7 +775,7 @@ end
 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
 #
 # The tricky point is that a single C variable can be associated to more than one RuntimeVariable because the static knowledge of the type of an expression can vary in the C code.
-private class RuntimeVariable
+class RuntimeVariable
        # The name of the variable in the C code
        var name: String
 
@@ -733,11 +783,11 @@ private class RuntimeVariable
        var mtype: MType
 
        # The current casted type of the variable (as known in Nit)
-       var mcasttype: MType
+       var mcasttype: MType writable
 
        # If the variable exaclty a mcasttype?
        # false (usual value) means that the variable is a mcasttype or a subtype.
-       var is_exact: Bool = false
+       var is_exact: Bool writable = false
 
        init(name: String, mtype: MType, mcasttype: MType)
        do
@@ -770,7 +820,7 @@ end
 
 # A visitor on the AST of property definition that generate the C code.
 # Because of inlining, a visitor can visit more than one property.
-private class GlobalCompilerVisitor
+class GlobalCompilerVisitor
        # The associated compiler
        var compiler: GlobalCompiler
 
@@ -795,11 +845,11 @@ private class GlobalCompilerVisitor
        # Force to get the primitive property named `name' in the instance `recv' or abort
        fun get_property(name: String, recv: MType): MMethod
        do
-               return self.compiler.mainmodule.force_get_primitive_method(name, recv)
+               return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
        end
 
        # The current Frame
-       var frame: nullable Frame
+       var frame: nullable Frame writable
 
        # Anchor a type to the main module and the current receiver
        fun anchor(mtype: MType): MType
@@ -826,7 +876,7 @@ private class GlobalCompilerVisitor
        private var decl_lines: List[String] = new List[String]
 
        # The current visited AST node
-       var current_node: nullable AExpr = null
+       var current_node: nullable ANode = null
 
        # Compile an expression an return its result
        # `mtype` is the expected return type, pass null if no specific type is expected.
@@ -871,7 +921,7 @@ private class GlobalCompilerVisitor
                if value.mtype.ctype == mtype.ctype then
                        return value
                else if value.mtype.ctype == "val*" then
-                       return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
+                       return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
                else if mtype.ctype == "val*" then
                        var valtype = value.mtype.as(MClassType)
                        var res = self.new_var(mtype)
@@ -938,6 +988,15 @@ private class GlobalCompilerVisitor
                return res
        end
 
+       # Return a new uninitialized named runtime_variable
+       fun new_named_var(mtype: MType, name: String): RuntimeVariable
+       do
+               mtype = self.anchor(mtype)
+               var res = new RuntimeVariable(name, mtype, mtype)
+               self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
+               return res
+       end
+
        # Return a new local runtime_variable initialized with the C expression `cexpr'.
        fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
        do
@@ -1040,6 +1099,28 @@ private class GlobalCompilerVisitor
                return res
        end
 
+       fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable])
+       do
+               var elttype = arguments.first.mtype
+               var recv = "((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->values"
+               if pname == "[]" then
+                       self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
+                       return
+               else if pname == "[]=" then
+                       self.add("{recv}[{arguments[1]}]={arguments[2]};")
+                       return
+               else if pname == "copy_to" then
+                       var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values"
+                       self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));")
+                       return
+               end
+       end
+
+       fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable])
+       do
+               self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type))
+       end
+
        # Generate a polymorphic send for the method `m' and the arguments `args'
        fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
        do
@@ -1138,6 +1219,21 @@ private class GlobalCompilerVisitor
                return res
        end
 
+       # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
+       fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
+       do
+               assert t isa MClassType
+               var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
+               if propdefs.length == 0 then
+                       abort
+               end
+               if propdefs.length > 1 then
+                       self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
+               end
+               var propdef = propdefs.first
+               return self.call(propdef, t, args)
+       end
+
        fun check_valid_reciever(recvtype: MClassType)
        do
                if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
@@ -1184,7 +1280,11 @@ private class GlobalCompilerVisitor
                else
                        args = args.to_a
                end
-               assert args.length == m.msignature.arity + 1 # because of self
+               if args.length != m.msignature.arity + 1 then # because of self
+                       add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
+                       debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
+                       return null
+               end
 
                args.first = recv
                var rm = new CustomizedRuntimeFunction(m, recvtype)
@@ -1210,6 +1310,48 @@ private class GlobalCompilerVisitor
                self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
        end
 
+       # Generate a polymorphic attribute is_set test
+       fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
+       do
+               var types = self.collect_types(recv)
+
+               var res = self.new_var(bool_type)
+
+               if types.is_empty then
+                       self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
+                       return res
+               end
+               self.add("/* isset {a} on {recv.inspect} */")
+               self.add("switch({recv}->classid) \{")
+               var last = types.last
+               for t in types do
+                       if not self.compiler.hardening and t == last then
+                               self.add("default: /*{self.compiler.classid(t)}*/")
+                       else
+                               self.add("case {self.compiler.classid(t)}:")
+                       end
+                       var recv2 = self.autoadapt(recv, t)
+                       var ta = a.intro.static_mtype.as(not null)
+                       ta = self.resolve_for(ta, recv2)
+                       var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
+                       if not ta isa MNullableType then
+                               if ta.ctype == "val*" then
+                                       self.add("{res} = ({attr} != NULL);")
+                               else
+                                       self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
+                               end
+                       end
+                       self.add("break;")
+               end
+               if self.compiler.hardening then
+                       self.add("default: /* Bug */")
+                       self.bugtype(recv)
+               end
+               self.add("\}")
+
+               return res
+       end
+
        # Generate a polymorphic attribute read
        fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
        do
@@ -1333,6 +1475,42 @@ private class GlobalCompilerVisitor
                return res
        end
 
+       # Generate the code required to dynamically check if 2 objects share the same runtime type
+       fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
+       do
+               var res = self.new_var(bool_type)
+               if value2.mtype.ctype == "val*" then
+                       if value1.mtype.ctype == "val*" then
+                               self.add "{res} = {value1}->classid == {value2}->classid;"
+                       else
+                               self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
+                       end
+               else
+                       if value1.mtype.ctype == "val*" then
+                               self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
+                       else if value1.mcasttype == value2.mcasttype then
+                               self.add "{res} = 1;"
+                       else
+                               self.add "{res} = 0;"
+                       end
+               end
+               return res
+       end
+
+       # Return a "const char*" variable associated to the classname of the dynamic type of an object
+       # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
+       fun class_name_string(value: RuntimeVariable): String
+       do
+               var res = self.get_name("var_class_name")
+               self.add_decl("const char* {res};")
+               if value.mtype.ctype == "val*" then
+                       self.add "{res} = class_names[{value}->classid];"
+               else
+                       self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
+               end
+               return res
+       end
+
        # Generate a Nit "is" for two runtime_variables
        fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
        do
@@ -1371,9 +1549,19 @@ private class GlobalCompilerVisitor
        end
 
        # Generate a check-init-instance
-       # TODO: is an empty stub currently
        fun check_init_instance(recv: RuntimeVariable)
        do
+               var mtype = self.anchor(recv.mcasttype)
+               for cd in mtype.collect_mclassdefs(self.compiler.mainmodule)
+               do
+                       var n = self.compiler.modelbuilder.mclassdef2nclassdef[cd]
+                       for npropdef in n.n_propdefs do
+                               if npropdef isa AAttrPropdef then
+                                       # Force read to check the initialization
+                                       self.read_attribute(npropdef.mpropdef.mproperty, recv)
+                               end
+                       end
+               end
        end
 
        # Generate an integer value
@@ -1388,17 +1576,18 @@ private class GlobalCompilerVisitor
        fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
        do
                elttype = self.anchor(elttype)
-               var res = self.init_instance(self.get_class("Array").get_mtype([elttype]))
+               var arraytype = self.get_class("Array").get_mtype([elttype])
+               var res = self.init_instance(arraytype)
                self.add("\{ /* {res} = array_instance Array[{elttype}] */")
                var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
                nat.is_exact = true
-               self.add("{nat} = GC_MALLOC({array.length} * sizeof({elttype.ctype}));")
+               self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
                for i in [0..array.length[ do
                        var r = self.autobox(array[i], elttype)
-                       self.add("{nat}[{i}] = {r};")
+                       self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
                end
                var length = self.int_instance(array.length)
-               self.send(self.get_property("with_native", res.mtype), [res, nat, length])
+               self.send(self.get_property("with_native", arraytype), [res, nat, length])
                self.check_init_instance(res)
                self.add("\}")
                return res
@@ -1419,7 +1608,7 @@ private class GlobalCompilerVisitor
                var res2 = self.init_instance(mtype)
                self.add("{res} = {res2};")
                var length = self.int_instance(string.length)
-               self.send(self.get_property("with_native", res.mtype), [res, nat, length])
+               self.send(self.get_property("with_native", mtype), [res, nat, length])
                self.check_init_instance(res)
                self.add("{name} = {res};")
                self.add("\}")
@@ -1440,7 +1629,7 @@ private class GlobalCompilerVisitor
 end
 
 # A frame correspond to a visited property in a GlobalCompilerVisitor
-private class Frame
+class Frame
        # The associated visitor
 
        var visitor: GlobalCompilerVisitor
@@ -1456,10 +1645,10 @@ private class Frame
        var arguments: Array[RuntimeVariable]
 
        # The runtime_variable associated to the return (in a function)
-       var returnvar: nullable RuntimeVariable = null
+       var returnvar: nullable RuntimeVariable writable = null
 
        # The label at the end of the property
-       var returnlabel: nullable String = null
+       var returnlabel: nullable String writable = null
 end
 
 redef class MPropDef
@@ -1478,7 +1667,7 @@ end
 
 redef class MMethodDef
        # Can the body be inlined?
-       private fun can_inline(v: GlobalCompilerVisitor): Bool
+       fun can_inline(v: GlobalCompilerVisitor): Bool
        do
                var modelbuilder = v.compiler.modelbuilder
                if modelbuilder.mpropdef2npropdef.has_key(self) then
@@ -1493,15 +1682,21 @@ redef class MMethodDef
        end
 
        # Inline the body in another visitor
-       private fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
+       fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                var modelbuilder = v.compiler.modelbuilder
                if modelbuilder.mpropdef2npropdef.has_key(self) then
                        var npropdef = modelbuilder.mpropdef2npropdef[self]
+                       var oldnode = v.current_node
+                       v.current_node = npropdef
                        npropdef.compile_to_c(v, self, arguments)
+                       v.current_node = oldnode
                else if self.mproperty.name == "init" then
                        var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
+                       var oldnode = v.current_node
+                       v.current_node = nclassdef
                        nclassdef.compile_to_c(v, self, arguments)
+                       v.current_node = oldnode
                else
                        abort
                end
@@ -1510,13 +1705,13 @@ redef class MMethodDef
 end
 
 redef class APropdef
-       private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+       fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
                v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
                debug("Not yet implemented")
        end
 
-       private fun can_inline: Bool do return true
+       fun can_inline: Bool do return true
 end
 
 redef class AConcreteMethPropdef
@@ -1538,7 +1733,6 @@ redef class AConcreteMethPropdef
                                end
                        end
                end
-
                v.stmt(self.n_block)
        end
 
@@ -1635,6 +1829,12 @@ redef class AInternMethPropdef
                        else if pname == "object_id" then
                                v.ret(arguments.first)
                                return
+                       else if pname == "+" then
+                               v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+                               return
+                       else if pname == "-" then
+                               v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+                               return
                        else if pname == "==" then
                                v.ret(v.equal_test(arguments[0], arguments[1]))
                                return
@@ -1766,17 +1966,8 @@ redef class AInternMethPropdef
                                return
                        end
                else if cname == "NativeArray" then
-                       var elttype = arguments.first.mtype
-                       if pname == "[]" then
-                               v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
-                               return
-                       else if pname == "[]=" then
-                               v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
-                               return
-                       else if pname == "copy_to" then
-                               v.add("memcpy({arguments[1]},{arguments[0]},{arguments[2]}*sizeof({elttype.ctype}));")
-                               return
-                       end
+                       v.native_array_def(pname, ret, arguments)
+                       return
                end
                if pname == "exit" then
                        v.add("exit({arguments[1]});")
@@ -1788,35 +1979,24 @@ redef class AInternMethPropdef
                        v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
                        return
                else if pname == "calloc_array" then
-                       var elttype = arguments.first.mtype.supertype_to(v.compiler.mainmodule,arguments.first.mtype.as(MClassType),v.get_class("ArrayCapable")).as(MGenericType).arguments.first
-                       v.ret(v.new_expr("({elttype.ctype}*)GC_MALLOC({arguments[1]} * sizeof({elttype.ctype}))", ret.as(not null)))
+                       v.calloc_array(ret.as(not null), arguments)
                        return
                else if pname == "object_id" then
                        v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
                        return
                else if pname == "is_same_type" then
-                       if arguments[0].mtype.ctype == "val*" then
-                               v.ret(v.new_expr("{arguments[0]}->classid == {arguments[1]}->classid", ret.as(not null)))
-                       else
-                               v.ret(v.new_expr("{v.compiler.classid(arguments[0].mtype.as(MClassType))} == {arguments[1]}->classid", ret.as(not null)))
-                       end
+                       v.ret(v.is_same_type_test(arguments[0], arguments[1]))
                        return
                else if pname == "output_class_name" then
-                       if arguments[0].mtype.ctype == "val*" then
-                               v.add("printf(\"%s\\n\", class_names[{arguments.first}->classid]);")
-                       else
-                               v.add("printf(\"%s\\n\", class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]);")
-                       end
+                       var nat = v.class_name_string(arguments.first)
+                       v.add("printf(\"%s\\n\", {nat});")
                        return
                else if pname == "native_class_name" then
-                       if arguments[0].mtype.ctype == "val*" then
-                               v.ret(v.new_expr("(char*)(void*)class_names[{arguments.first}->classid]", ret.as(not null)))
-                       else
-                               v.ret(v.new_expr("(char*)(void*)class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]", ret.as(not null)))
-                       end
+                       var nat = v.class_name_string(arguments.first)
+                       v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
                        return
                end
-               v.add("printf(\"NOT IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
+               v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
                debug("Not implemented {mpropdef}")
        end
 end
@@ -1841,6 +2021,7 @@ redef class AExternMethPropdef
                        ret = v.resolve_for(ret, arguments.first)
                        res = v.new_var(ret)
                end
+               v.adapt_signature(mpropdef, arguments)
 
                if res == null then
                        v.add("{externname}({arguments.join(", ")});")
@@ -1865,6 +2046,7 @@ redef class AExternInitPropdef
                        var file = location.file.filename
                        v.compiler.add_extern(file)
                end
+               v.adapt_signature(mpropdef, arguments)
                var ret = arguments.first.mtype
                var res = v.new_var(ret)
 
@@ -1886,7 +2068,7 @@ redef class AAttrPropdef
                end
        end
 
-       private fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
+       fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
        do
                var nexpr = self.n_expr
                if nexpr != null then
@@ -2121,21 +2303,31 @@ redef class AForExpr
        redef fun stmt(v)
        do
                var cl = v.expr(self.n_expr, null)
-               var it = v.send(v.get_property("iterator", cl.mtype), [cl])
+               var it_meth = self.method_iterator
+               assert it_meth != null
+               var it = v.send(it_meth, [cl])
                assert it != null
                v.add("for(;;) \{")
-               var ok = v.send(v.get_property("is_ok", it.mtype), [it])
+               var isok_meth = self.method_is_ok
+               assert isok_meth != null
+               var ok = v.send(isok_meth, [it])
                assert ok != null
                v.add("if(!{ok}) break;")
                if self.variables.length == 1 then
-                       var i = v.send(v.get_property("item", it.mtype), [it])
+                       var item_meth = self.method_item
+                       assert item_meth != null
+                       var i = v.send(item_meth, [it])
                        assert i != null
                        v.assign(v.variable(variables.first), i)
                else if self.variables.length == 2 then
-                       var i = v.send(v.get_property("key", it.mtype), [it])
+                       var key_meth = self.method_key
+                       assert key_meth != null
+                       var i = v.send(key_meth, [it])
                        assert i != null
                        v.assign(v.variable(variables[0]), i)
-                       i = v.send(v.get_property("item", it.mtype), [it])
+                       var item_meth = self.method_item
+                       assert item_meth != null
+                       i = v.send(item_meth, [it])
                        assert i != null
                        v.assign(v.variable(variables[1]), i)
                else
@@ -2143,7 +2335,9 @@ redef class AForExpr
                end
                v.stmt(self.n_block)
                v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
-               v.send(v.get_property("next", it.mtype), [it])
+               var next_meth = self.method_next
+               assert next_meth != null
+               v.send(next_meth, [it])
                v.add("\}")
                v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
        end
@@ -2251,7 +2445,7 @@ end
 redef class AArrayExpr
        redef fun expr(v)
        do
-               var mtype = self.mtype.as(MGenericType).arguments.first
+               var mtype = self.mtype.as(MClassType).arguments.first
                var array = new Array[RuntimeVariable]
                for nexpr in self.n_exprs.n_exprs do
                        var i = v.expr(nexpr, mtype)
@@ -2450,6 +2644,7 @@ redef class ASuperExpr
                # FIXME: we do not want an ugly static call!
                var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
                if mpropdefs.length != 1 then
+                       v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
                        debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
                end
                mpropdef = mpropdefs.first
@@ -2521,6 +2716,12 @@ redef class AAttrReassignExpr
 end
 
 redef class AIssetAttrExpr
+       redef fun expr(v)
+       do
+               var recv = v.expr(self.n_expr, null)
+               var mproperty = self.mproperty.as(not null)
+               return v.isset_attribute(mproperty, recv)
+       end
 end
 
 redef class ADebugTypeExpr