Merge branch 'master' into polymorphic_extern_classes
authorAlexis Laferrière <alexis.laf@xymus.net>
Wed, 10 Sep 2014 18:54:40 +0000 (14:54 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Wed, 10 Sep 2014 18:54:40 +0000 (14:54 -0400)
1  2 
lib/pnacl.nit
src/compiler/abstract_compiler.nit
src/compiler/compiler_ffi.nit
src/compiler/global_compiler.nit
src/compiler/separate_compiler.nit
src/compiler/separate_erasure_compiler.nit
src/model/model.nit
src/nit.nit
src/rapid_type_analysis.nit

diff --combined lib/pnacl.nit
  # Provides PNaCl support for Nit.
  module pnacl is platform
  
+ import standard
+ intrude import standard::stream
 -`{
 -      #include <unistd.h>
 -      #include <stddef.h>
 -      #include <stdio.h>
 -      #include <string.h>
 -      #include <stdlib.h>
 -      #include <pthread.h>
 +in "C Header" `{
        #include "ppapi/c/pp_errors.h"
        #include "ppapi/c/ppp.h"
        #include "ppapi/c/ppp_instance.h"
        #include "ppapi/c/ppp_messaging.h"
        #include "ppapi/c/ppb_var_dictionary.h"
        #include "ppapi/c/ppb_var_array.h"
 +`}
 +
 +`{
 +      #include <unistd.h>
 +      #include <stddef.h>
 +      #include <stdio.h>
 +      #include <string.h>
 +      #include <stdlib.h>
 +      #include <pthread.h>
  
        #define MAX_DICTIONARY_QUEUE_SIZE 200
        #define MAX_MESSAGE_QUEUE_SIZE 10
  module abstract_compiler
  
  import literal
- import typing
- import auto_super_init
+ import semantize
  import platform
  import c_tools
+ private import annotation
  
  # Add compiling options
  redef class ToolContext
@@@ -395,7 -395,7 +395,7 @@@ class MakefileToolchai
                        if f.compiles_to_o_file then ofiles.add(o)
                        if f.add_to_jar then java_files.add(f)
                end
-               
                if not java_files.is_empty then
                        var jar_file = "{outpath}.jar"
  
@@@ -445,13 -445,13 +445,13 @@@ abstract class AbstractCompile
  
        # The main module of the program currently compiled
        # Is assigned during the separate compilation
-       var mainmodule: MModule writable
+       var mainmodule: MModule is writable
  
        # The real main module of the program
        var realmainmodule: MModule
  
        # The modeulbuilder used to know the model and the AST
-       var modelbuilder: ModelBuilder protected writable
+       var modelbuilder: ModelBuilder is protected writable
  
        # Is hardening asked? (see --hardening)
        fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
        fun new_visitor: VISITOR is abstract
  
        # Where global declaration are stored (the main .h)
-       var header: CodeWriter writable
+       var header: CodeWriter is writable
  
        # Provide a declaration that can be requested (before or latter) by a visitor
        fun provide_declaration(key: String, s: String)
@@@ -643,10 -643,12 +643,12 @@@ extern void nitni_global_ref_decr( stru
        end
  
        # Generate the main C function.
+       #
        # This function:
-       #       * allocate the Sys object if it exists
-       #       * call init if is exists
-       #       * call main if it exists
+       #
+       # * allocate the Sys object if it exists
+       # * call init if is exists
+       # * call main if it exists
        fun compile_main_function
        do
                var v = self.new_visitor
@@@ -930,12 -932,13 +932,13 @@@ extern void nitni_global_ref_decr( stru
        end
  
        # Display stats about compilation process
+       #
        # Metrics used:
-       #       * type tests against resolved types (`x isa Collection[Animal]`)
-       #       * type tests against unresolved types (`x isa Collection[E]`)
-       #       * type tests skipped
-       #       * type tests total
-       #       *
+       #
+       # * type tests against resolved types (`x isa Collection[Animal]`)
+       # * type tests against unresolved types (`x isa Collection[E]`)
+       # * type tests skipped
+       # * type tests total
        fun display_stats
        do
                if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
@@@ -1015,10 -1018,10 +1018,10 @@@ abstract class AbstractCompilerVisito
        var compiler: COMPILER
  
        # The current visited AST node
-       var current_node: nullable ANode writable = null
+       var current_node: nullable ANode = null is writable
  
        # The current `Frame`
-       var frame: nullable Frame writable
+       var frame: nullable Frame is writable
  
        # Alias for self.compiler.mainmodule.object_type
        fun object_type: MClassType do return self.compiler.mainmodule.object_type
        # Generate a super call from a method definition
        fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
  
 +      # Adapt the arguments of a method according to targetted `MMethodDef`
        fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
  
 +      # Unbox all the arguments of a method when implemented `extern` or `intern`
 +      fun unbox_signature_extern(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
 +
        # Box or unbox a value to another type iff a C type conversion is needed
        # ENSURE: `result.mtype.ctype == mtype.ctype`
        fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
  
 +      # Box extern classes to be used in the generated code
 +      fun box_extern(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
 +
 +      # Unbox extern classes to be used in extern code (legacy NI and FFI)
 +      fun unbox_extern(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
 +
        #  Generate a polymorphic subtype test
        fun type_test(value: RuntimeVariable, mtype: MType, tag: String): RuntimeVariable is abstract
  
        private var escapemark_names = new HashMap[EscapeMark, String]
  
        # 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
+       # 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 is abstract
  
        # Variables handling
                return res
        end
  
 +      # The difference with `new_var` is the C static type of the local variable
 +      fun new_var_extern(mtype: MType): RuntimeVariable
 +      do
 +              mtype = self.anchor(mtype)
 +              var name = self.get_name("var")
 +              var res = new RuntimeVariable(name, mtype, mtype)
 +              self.add_decl("{mtype.ctype_extern} {name} /* : {mtype} for extern */;")
 +              return res
 +      end
 +
        # Return a new uninitialized named runtime_variable
        fun new_named_var(mtype: MType, name: String): RuntimeVariable
        do
                var mtype = recv.mtype
                var finalizable_type = compiler.mainmodule.finalizable_type
                if finalizable_type != null and not mtype.need_anchor and
-                  mtype.is_subtype(compiler.mainmodule, null, finalizable_type) then
+                               mtype.is_subtype(compiler.mainmodule, null, finalizable_type) then
                        add "gc_register_finalizer({recv});"
                end
        end
@@@ -1541,7 -1524,7 +1544,7 @@@ abstract class AbstractRuntimeFunctio
        # Non cached version of `c_name`
        protected fun build_c_name: String is abstract
  
-       protected var c_name_cache: nullable String writable = null
+       protected var c_name_cache: nullable String = null is writable
  
        # Implements a call of the runtime_function
        # May inline the body or generate a C function call
@@@ -1564,11 -1547,11 +1567,11 @@@ class RuntimeVariabl
        var mtype: MType
  
        # The current casted type of the variable (as known in Nit)
-       var mcasttype: MType writable
+       var mcasttype: MType is writable
  
        # If the variable exaclty a mcasttype?
        # false (usual value) means that the variable is a mcasttype or a subtype.
-       var is_exact: Bool writable = false
+       var is_exact: Bool = false is writable
  
        init(name: String, mtype: MType, mcasttype: MType)
        do
@@@ -1618,25 -1601,21 +1621,25 @@@ class Fram
        var arguments: Array[RuntimeVariable]
  
        # The runtime_variable associated to the return (in a function)
-       var returnvar: nullable RuntimeVariable writable = null
+       var returnvar: nullable RuntimeVariable = null is writable
  
        # The label at the end of the property
-       var returnlabel: nullable String writable = null
+       var returnlabel: nullable String = null is writable
  end
  
  redef class MType
        # Return the C type associated to a given Nit static type
        fun ctype: String do return "val*"
  
 +      # C type outside of the compiler code and in boxes
 +      fun ctype_extern: String do return "val*"
 +
 +      # Short name of the `ctype` to use in unions
        fun ctypename: String do return "val"
  
        # Return the name of the C structure associated to a Nit live type
        fun c_name: String is abstract
-       protected var c_name_cache: nullable String protected writable
+       protected var c_name_cache: nullable String is protected writable
  end
  
  redef class MClassType
                        return "char*"
                else if mclass.name == "NativeArray" then
                        return "val*"
 -              else if mclass.kind == extern_kind then
 -                      return "void*"
                else
                        return "val*"
                end
        end
  
 +      redef fun ctype_extern: String
 +      do
 +              if mclass.kind == extern_kind then
 +                      return "void*"
 +              else
 +                      return ctype
 +              end
 +      end
 +
        redef fun ctypename: String
        do
                if mclass.name == "Int" then
                else if mclass.name == "NativeArray" then
                        #return "{self.arguments.first.ctype}*"
                        return "val"
 -              else if mclass.kind == extern_kind then
 -                      return "ptr"
                else
                        return "val"
                end
@@@ -1889,6 -1863,18 +1892,18 @@@ redef class AMethPropde
                        v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
                end
  
+               # Try special compilation
+               if mpropdef.is_intern then
+                       if compile_intern_to_c(v, mpropdef, arguments) then return
+               else if mpropdef.is_extern then
+                       if mpropdef.mproperty.is_init then
+                               if compile_externinit_to_c(v, mpropdef, arguments) then return
+                       else
+                               if compile_externmeth_to_c(v, mpropdef, arguments) then return
+                       end
+               end
+               # Compile block if any
                var n_block = n_block
                if n_block != null then
                        for i in [0..mpropdef.msignature.arity[ do
                                v.assign(v.variable(variable), arguments[i+1])
                        end
                        v.stmt(n_block)
-               else if mpropdef.is_intern then
-                       compile_intern_to_c(v, mpropdef, arguments)
-               else if mpropdef.is_extern then
-                       if mpropdef.mproperty.is_init then
-                               compile_externinit_to_c(v, mpropdef, arguments)
-                       else
-                               compile_externmeth_to_c(v, mpropdef, arguments)
-                       end
-               else
-                       abort
+                       return
                end
+               # We have a problem
+               var cn = v.class_name_string(arguments.first)
+               v.add("PRINT_ERROR(\"Runtime error: uncompiled method `%s` called on `%s`. NOT YET IMPLEMENTED\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
+               v.add_raw_abort
        end
  
        redef fun can_inline
                return false
        end
  
-       fun compile_intern_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+       fun compile_intern_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool
        do
                var pname = mpropdef.mproperty.name
                var cname = mpropdef.mclassdef.mclass.name
                end
                if pname != "==" and pname != "!=" then
                        v.adapt_signature(mpropdef, arguments)
 +                      v.unbox_signature_extern(mpropdef, arguments)
                end
                if cname == "Int" then
                        if pname == "output" then
                                v.add("printf(\"%ld\\n\", {arguments.first});")
-                               return
+                               return true
                        else if pname == "object_id" then
                                v.ret(arguments.first)
-                               return
+                               return true
                        else if pname == "+" then
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "-" then
                                v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "unary -" then
                                v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "*" then
                                v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "/" then
                                v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "%" then
                                v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "lshift" then
                                v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "rshift" then
                                v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "==" then
                                v.ret(v.equal_test(arguments[0], arguments[1]))
-                               return
+                               return true
                        else if pname == "!=" then
                                var res = v.equal_test(arguments[0], arguments[1])
                                v.ret(v.new_expr("!{res}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "<" then
                                v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == ">" then
                                v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "<=" then
                                v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == ">=" then
                                v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "to_f" then
                                v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "ascii" then
                                v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return
+                               return true
                        end
                else if cname == "Char" then
                        if pname == "output" then
                                v.add("printf(\"%c\", {arguments.first});")
-                               return
+                               return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "successor" then
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "predecessor" then
                                v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "==" then
                                v.ret(v.equal_test(arguments[0], arguments[1]))
-                               return
+                               return true
                        else if pname == "!=" then
                                var res = v.equal_test(arguments[0], arguments[1])
                                v.ret(v.new_expr("!{res}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "<" then
                                v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == ">" then
                                v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "<=" then
                                v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == ">=" then
                                v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "to_i" then
                                v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "ascii" then
                                v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
-                               return
+                               return true
                        end
                else if cname == "Bool" then
                        if pname == "output" then
                                v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
-                               return
+                               return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "==" then
                                v.ret(v.equal_test(arguments[0], arguments[1]))
-                               return
+                               return true
                        else if pname == "!=" then
                                var res = v.equal_test(arguments[0], arguments[1])
                                v.ret(v.new_expr("!{res}", ret.as(not null)))
-                               return
+                               return true
                        end
                else if cname == "Float" then
                        if pname == "output" then
                                v.add("printf(\"%f\\n\", {arguments.first});")
-                               return
+                               return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "+" then
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "-" then
                                v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "unary -" then
                                v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "succ" then
                                v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "prec" then
                                v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "*" then
                                v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "/" then
                                v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "==" then
                                v.ret(v.equal_test(arguments[0], arguments[1]))
-                               return
+                               return true
                        else if pname == "!=" then
                                var res = v.equal_test(arguments[0], arguments[1])
                                v.ret(v.new_expr("!{res}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "<" then
                                v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == ">" then
                                v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "<=" then
                                v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == ">=" then
                                v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "to_i" then
                                v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
-                               return
+                               return true
                        end
                else if cname == "NativeString" then
                        if pname == "[]" then
                                v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "[]=" then
                                v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
-                               return
+                               return true
                        else if pname == "copy_to" then
                                v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
-                               return
+                               return true
                        else if pname == "atoi" then
                                v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
-                               return
+                               return true
                        else if pname == "init" then
                                v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
-                               return
+                               return true
                        end
                else if cname == "NativeArray" then
                        v.native_array_def(pname, ret, arguments)
-                       return
+                       return true
                end
                if pname == "exit" then
                        v.add("exit({arguments[1]});")
-                       return
+                       return true
                else if pname == "sys" then
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
-                       return
+                       return true
                else if pname == "calloc_string" then
                        v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
-                       return
+                       return true
                else if pname == "calloc_array" then
                        v.calloc_array(ret.as(not null), arguments)
-                       return
+                       return true
                else if pname == "object_id" then
                        v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
-                       return
+                       return true
                else if pname == "is_same_type" then
                        v.ret(v.is_same_type_test(arguments[0], arguments[1]))
-                       return
+                       return true
                else if pname == "is_same_instance" then
                        v.ret(v.equal_test(arguments[0], arguments[1]))
-                       return
+                       return true
                else if pname == "output_class_name" then
                        var nat = v.class_name_string(arguments.first)
                        v.add("printf(\"%s\\n\", {nat});")
-                       return
+                       return true
                else if pname == "native_class_name" then
                        var nat = v.class_name_string(arguments.first)
                        v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
-                       return
+                       return true
                else if pname == "force_garbage_collection" then
                        v.add("nit_gcollect();")
-                       return
+                       return true
                else if pname == "native_argc" then
                        v.ret(v.new_expr("glob_argc", ret.as(not null)))
-                       return
+                       return true
                else if pname == "native_argv" then
                        v.ret(v.new_expr("glob_argv[{arguments[1]}]", ret.as(not null)))
-                       return
+                       return true
                end
-               v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
-               debug("Not implemented {mpropdef}")
+               return false
        end
  
-       fun compile_externmeth_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+       # Compile an extern method
+       # Return `true` if the compilation was successful, `false` if a fall-back is needed
+       fun compile_externmeth_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool
        do
                var externname
-               var nextern = self.n_extern
-               if nextern == null then
-                       v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
-                       v.add("show_backtrace(1);")
-                       return
+               var at = self.get_single_annotation("extern", v.compiler.modelbuilder)
+               if at != null then
+                       externname = at.arg_as_string(v.compiler.modelbuilder)
+                       if externname == null then return false
+               else
+                       var nextern = self.n_extern
+                       if nextern == null then return false
+                       externname = nextern.text.substring(1, nextern.text.length-2)
                end
-               externname = nextern.text.substring(1, nextern.text.length-2)
                if location.file != null then
                        var file = location.file.filename
                        v.add_extern(file)
                var ret = mpropdef.msignature.return_mtype
                if ret != null then
                        ret = v.resolve_for(ret, arguments.first)
 -                      res = v.new_var(ret)
 +                      res = v.new_var_extern(ret)
                end
                v.adapt_signature(mpropdef, arguments)
 +              v.unbox_signature_extern(mpropdef, arguments)
  
                if res == null then
                        v.add("{externname}({arguments.join(", ")});")
                else
                        v.add("{res} = {externname}({arguments.join(", ")});")
 +                      res = v.box_extern(res, ret.as(not null))
                        v.ret(res)
                end
+               return true
        end
  
-       fun compile_externinit_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+       # Compile an extern factory
+       # Return `true` if the compilation was successful, `false` if a fall-back is needed
+       fun compile_externinit_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool
        do
                var externname
-               var nextern = self.n_extern
-               if nextern == null then
-                       v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
-                       v.add("show_backtrace(1);")
-                       return
+               var at = self.get_single_annotation("extern", v.compiler.modelbuilder)
+               if at != null then
+                       externname = at.arg_as_string(v.compiler.modelbuilder)
+                       if externname == null then return false
+               else
+                       var nextern = self.n_extern
+                       if nextern == null then return false
+                       externname = nextern.text.substring(1, nextern.text.length-2)
                end
-               externname = nextern.text.substring(1, nextern.text.length-2)
                if location.file != null then
                        var file = location.file.filename
                        v.add_extern(file)
                end
                v.adapt_signature(mpropdef, arguments)
 +              v.unbox_signature_extern(mpropdef, arguments)
                var ret = arguments.first.mtype
 -              var res = v.new_var(ret)
 +              var res = v.new_var_extern(ret)
  
                arguments.shift
  
                v.add("{res} = {externname}({arguments.join(", ")});")
 +              res = v.box_extern(res, ret)
                v.ret(res)
+               return true
        end
  end
  
@@@ -2907,7 -2893,7 +2927,7 @@@ redef class ANewExp
                        return v.native_array_instance(elttype, l)
                else if ctype == "val*" then
                        recv = v.init_instance(mtype)
 -              else if ctype == "void*" then
 +              else if ctype == "char*" then
                        recv = v.new_expr("NULL/*special!*/", mtype)
                else
                        recv = v.new_expr("({ctype})0/*special!*/", mtype)
@@@ -3053,4 -3039,3 +3073,3 @@@ for mmodule in mmodules d
        end
        toolcontext.run_global_phases(ms)
  end
@@@ -110,8 -110,6 +110,6 @@@ redef class AMethPropde
                amodule.ensure_compile_ffi_wrapper
                compile_ffi_method(mmodule)
  
-               assert self isa AExternPropdef
                # nitni - Compile missing callbacks
                mmodule.ensure_compile_nitni_base(v)
                var ccu = mmodule.nitni_ccu.as(not null)
  
        redef fun compile_externmeth_to_c(v, mpropdef, arguments)
        do
-               var mmodule = mpropdef.mclassdef.mmodule
                # if using the old native interface fallback on previous implementation
-               var nextern = self.n_extern
-               if nextern != null then
-                       super
-                       return
-               end
+               if n_extern_code_block == null then return super
  
+               var mmodule = mpropdef.mclassdef.mmodule
                mmodule.uses_ffi = true
  
                var mclass_type = mpropdef.mclassdef.bound_mtype
                end
  
                v.adapt_signature(mpropdef, arguments)
 +              v.unbox_signature_extern(mpropdef, arguments)
  
                var arguments_for_c = new Array[String]
                for a in [0..arguments.length[ do
                                v.add("ret_var = {externname}({arguments_for_c.join(", ")});")
                                v.add("{recv_var} = ret_var->value;")
                        end
 +                      recv_var = v.box_extern(recv_var, return_mtype)
                        v.ret(recv_var)
                end
  
                compile_ffi_support_to_c(v)
+               return true
        end
  
        redef fun compile_externinit_to_c(v, mpropdef, arguments)
        do
-               var mmodule = mpropdef.mclassdef.mmodule
                # if using the old native interface fallback on previous implementation
-               var nextern = self.n_extern
-               if nextern != null then
-                       super
-                       return
-               end
+               if n_extern_code_block == null then return super
  
+               var mmodule = mpropdef.mclassdef.mmodule
                mmodule.uses_ffi = true
  
                var mclass_type = mpropdef.mclassdef.bound_mtype
                var recv_var = v.new_var(return_mtype)
  
                v.adapt_signature(mpropdef, arguments)
 +              v.unbox_signature_extern(mpropdef, arguments)
  
                arguments.shift
  
                        v.add("ret_var = {externname}({arguments_for_c.join(", ")});")
                        v.add("{recv_var} = ret_var->value;")
                end
 +              recv_var = v.box_extern(recv_var, return_mtype)
                v.ret(recv_var)
  
                compile_ffi_support_to_c(v)
+               return true
        end
  end
  
@@@ -346,7 -332,7 +336,7 @@@ redef class MNullableTyp
                var base_cname = "null_{mtype.mangled_cname}"
                var full_cname = "NIT_NULL___{base_cname}"
  
-               # In nitni files, declare internal function as extern 
+               # In nitni files, declare internal function as extern
                var full_friendly_csignature = "{cname_blind} {full_cname}()"
                ccu.header_decl.add("extern {full_friendly_csignature};\n")
  
@@@ -378,7 -364,7 +368,7 @@@ redef class MExplicitCal
                var mproperty = mproperty
                assert mproperty isa MMethod
  
-               # In nitni files, declare internal function as extern 
+               # In nitni files, declare internal function as extern
                var full_friendly_csignature = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context)
                ccu.header_decl.add("extern {full_friendly_csignature};\n")
  
                var mtype: MType = recv_mtype
                var recv_var = null
                if mproperty.is_init then
 -                      if recv_mtype.mclass.kind == extern_kind then
 -                              recv_var = nitni_visitor.new_var(mtype)
 -                      else
 -                              var recv_mtype = recv_mtype
 -                              recv_var = nitni_visitor.init_instance(recv_mtype)
 -                              nitni_visitor.add("{mtype.ctype} recv /* var self: {mtype} */;")
 -                              nitni_visitor.add("recv = {recv_var};")
 -                      end
 +                      var recv_mtype = recv_mtype
 +                      recv_var = nitni_visitor.init_instance(recv_mtype)
 +                      nitni_visitor.add("{mtype.ctype} recv /* var self: {mtype} */;")
 +                      nitni_visitor.add("recv = {recv_var};")
                else
                        mtype = mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
                        recv_var = nitni_visitor.var_from_c("recv", mtype)
 +                      recv_var = nitni_visitor.box_extern(recv_var, mtype)
                end
  
                vars.add(recv_var)
                for p in msignature.mparameters do
                        var arg_mtype = p.mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
                        var arg = nitni_visitor.var_from_c(p.name, arg_mtype)
 +                      arg = nitni_visitor.box_extern(arg, arg_mtype)
                        vars.add(arg)
                end
  
                        assert ret_var != null
                        return_mtype = return_mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
                        ret_var = nitni_visitor.autobox(ret_var, return_mtype)
 +                      ret_var = nitni_visitor.unbox_extern(ret_var, return_mtype)
                        nitni_visitor.ret_to_c(ret_var, return_mtype)
                end
                nitni_visitor.add("\}")
@@@ -462,13 -449,11 +452,13 @@@ redef class MExplicitSupe
                var vars = new Array[RuntimeVariable]
  
                var recv_var = nitni_visitor.var_from_c("recv", mclass_type)
 +              recv_var = nitni_visitor.box_extern(recv_var, mclass_type)
                vars.add(recv_var)
  
                for p in msignature.mparameters do
                        var arg_mtype = v.anchor(p.mtype)
                        var arg = nitni_visitor.var_from_c(p.name, arg_mtype)
 +                      arg = nitni_visitor.box_extern(arg, arg_mtype)
                        vars.add(arg)
                end
  
                if return_mtype != null then
                        assert ret_var != null
                        return_mtype = v.anchor(return_mtype)
 +                      ret_var = nitni_visitor.autobox(ret_var, return_mtype)
 +                      ret_var = nitni_visitor.unbox_extern(ret_var, return_mtype)
                        nitni_visitor.ret_to_c(ret_var, return_mtype)
                end
                nitni_visitor.add("\}")
@@@ -496,7 -479,7 +486,7 @@@ redef class MExplicitCas
                ## check type
                #
  
-               # In nitni files, declare internal function as extern 
+               # In nitni files, declare internal function as extern
                var full_friendly_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind})"
                ccu.header_decl.add("extern {full_friendly_csignature};\n")
  
                var nitni_visitor = v.compiler.new_visitor
                nitni_visitor.frame = v.frame
  
 -              var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind} from)"
 +              var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
 +
                nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
                nitni_visitor.add_decl("{full_internal_csignature} \{")
  
 -              var from_var = new RuntimeVariable("from->value", from, from)
 +              #var from_var = new RuntimeVariable("from->value", from, from)
 +              var from_var = nitni_visitor.var_from_c("from", from)
 +              from_var = nitni_visitor.box_extern(from_var, from)
                var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
                nitni_visitor.add("return {recv_var};")
  
                nitni_visitor = v.compiler.new_visitor
                nitni_visitor.frame = v.frame
  
 -              full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({from.cname_blind} from)"
 +              full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
                nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
                nitni_visitor.add_decl("{full_internal_csignature} \{")
  
                from_var = nitni_visitor.var_from_c("from", from)
 +              from_var = nitni_visitor.box_extern(from_var, from)
  
                ## test type
                var check = nitni_visitor.type_test(from_var, to, "FFI cast")
  
                ## internal cast
                recv_var = nitni_visitor.autobox(from_var, to)
 +              recv_var = nitni_visitor.unbox_extern(recv_var, to)
  
                nitni_visitor.ret_to_c(recv_var, to)
  
@@@ -61,9 -61,6 +61,9 @@@ redef class ModelBuilde
                var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
                compiler.compile_header
  
 +              if mainmodule.model.get_mclasses_by_name("Pointer") != null then
 +                      runtime_type_analysis.live_types.add(mainmodule.pointer_type)
 +              end
                for t in runtime_type_analysis.live_types do
                        compiler.declare_runtimeclass(t)
                end
@@@ -74,9 -71,6 +74,9 @@@
                for t in runtime_type_analysis.live_types do
                        if t.ctype == "val*" then
                                compiler.generate_init_instance(t)
 +                              if t.mclass.kind == extern_kind then
 +                                      compiler.generate_box_instance(t)
 +                              end
                        else
                                compiler.generate_box_instance(t)
                        end
@@@ -122,7 -116,7 +122,7 @@@ class GlobalCompile
                self.runtime_type_analysis = runtime_type_analysis
                self.live_primitive_types = new Array[MClassType]
                for t in runtime_type_analysis.live_types do
 -                      if t.ctype != "val*" then
 +                      if t.ctype != "val*" or t.mclass.name == "Pointer" then
                                self.live_primitive_types.add(t)
                        end
                end
                        v.add_decl("{mtype.arguments.first.ctype} values[1];")
                end
  
 -              if mtype.ctype != "val*" then
 +              if mtype.ctype_extern != "val*" then
                        # Is the Nit type is native then the struct is a box with two fields:
                        # * the `classid` to be polymorph
                        # * the `value` that contains the native value.
 -                      v.add_decl("{mtype.ctype} value;")
 +                      v.add_decl("{mtype.ctype_extern} value;")
                end
  
                # Collect all attributes and associate them a field in the structure.
        fun generate_box_instance(mtype: MClassType)
        do
                assert self.runtime_type_analysis.live_types.has(mtype)
 -              assert mtype.ctype != "val*"
                var v = self.new_visitor
  
                self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
@@@ -323,34 -318,6 +323,34 @@@ class GlobalCompilerVisito
                end
        end
  
 +      redef fun unbox_extern(value, mtype)
 +      do
 +              if mtype isa MClassType and mtype.mclass.kind == extern_kind and
 +                 mtype.mclass.name != "NativeString" then
 +                      var res = self.new_var_extern(mtype)
 +                      self.add "{res} = ((struct {mtype.c_name}*){value})->value; /* unboxing {value.mtype} */"
 +                      return res
 +              else
 +                      return value
 +              end
 +      end
 +
 +      redef fun box_extern(value, mtype)
 +      do
 +              if not mtype isa MClassType or mtype.mclass.kind != extern_kind or
 +                      mtype.mclass.name == "NativeString" then return value
 +
 +              var valtype = value.mtype.as(MClassType)
 +              var res = self.new_var(mtype)
 +              if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
 +                      self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
 +                      self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                      return res
 +              end
 +              self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
 +              return res
 +      end
 +
        # The runtime types that are acceptable for a given receiver.
        fun collect_types(recv: RuntimeVariable): Array[MClassType]
        do
        do
                var recv_type = get_recvtype(m, recvtype, args)
                var recv = get_recv(recv_type, args)
 +              if m.is_extern then recv = unbox_extern(recv, recv_type)
                var new_args = args.to_a
                self.varargize(m, m.msignature.as(not null), new_args)
                new_args.first = recv
        do
                var recv_type = get_recvtype(m, recvtype, args)
                var recv = get_recv(recv_type, args)
 +              if m.is_extern then recv = unbox_extern(recv, recv_type)
                var new_args = args.to_a
                new_args.first = recv
                return finalize_call(m, recv_type, new_args)
                end
        end
  
 +      redef fun unbox_signature_extern(m, args)
 +      do
 +              var recv = args.first
 +              for i in [0..m.msignature.arity[ do
 +                      var t = m.msignature.mparameters[i].mtype
 +                      if i == m.msignature.vararg_rank then
 +                              t = args[i+1].mtype
 +                      end
 +                      t = self.resolve_for(t, recv)
 +                      if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
 +              end
 +      end
 +
        # FIXME: this is currently buggy since recv is not exact
        redef fun vararg_instance(mpropdef, recv, varargs, elttype)
        do
                                if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
                                s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
                        end
 +
 +                      if self.compiler.mainmodule.model.get_mclasses_by_name("Pointer") != null then
 +                              var pointer_type = self.compiler.mainmodule.pointer_type
 +                              if value1.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) or
 +                                      value2.mcasttype.is_subtype(self.compiler.mainmodule, null, pointer_type) then
 +                                      s.add "(((struct {pointer_type.c_name}*){value1})->value == ((struct {pointer_type.c_name}*){value2})->value)"
 +                              end
 +                      end
 +
                        if s.is_empty then
                                self.add("{res} = {value1} == {value2};")
                        else
@@@ -191,11 -191,7 +191,11 @@@ class SeparateCompile
                        self.header.add_decl("void* val;")
                        for c, v in self.box_kinds do
                                var t = c.mclass_type
 -                              self.header.add_decl("{t.ctype} {t.ctypename};")
 +
 +                              # `Pointer` reuse the `val` field
 +                              if t.mclass.name == "Pointer" then continue
 +
 +                              self.header.add_decl("{t.ctype_extern} {t.ctypename};")
                        end
                        self.header.add_decl("\} nitattribute_t; /* general C type representing a Nit attribute. */")
                end
  
        fun box_kind_of(mclass: MClass): Int
        do
 -              if mclass.mclass_type.ctype == "val*" then
 +              #var pointer_type = self.mainmodule.pointer_type
 +              #if mclass.mclass_type.ctype == "val*" or mclass.mclass_type.is_subtype(self.mainmodule, mclass.mclass_type pointer_type) then
 +              if mclass.mclass_type.ctype_extern == "val*" then
                        return 0
 -              else if mclass.kind == extern_kind then
 +              else if mclass.kind == extern_kind and mclass.name != "NativeString" then
                        return self.box_kinds[self.mainmodule.get_primitive_class("Pointer")]
                else
                        return self.box_kinds[mclass]
        do
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 -              var c_instance_name = mclass.c_instance_name
  
                var vft = self.method_tables[mclass]
                var attrs = self.attr_tables[mclass]
                var v = new_visitor
  
                var rta = runtime_type_analysis
 -              var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray"
 +              var is_dead = rta != null and not rta.live_classes.has(mclass) and mtype.ctype == "val*" and mclass.name != "NativeArray" and mclass.name != "Pointer"
  
                v.add_decl("/* runtime class {c_name} */")
  
                        v.add_decl("\};")
                end
  
 -              if mtype.ctype != "val*" then
 -                      if mtype.mclass.name == "Pointer" or mtype.mclass.kind != extern_kind then
 -                              #Build instance struct
 -                              self.header.add_decl("struct instance_{c_instance_name} \{")
 -                              self.header.add_decl("const struct type *type;")
 -                              self.header.add_decl("const struct class *class;")
 -                              self.header.add_decl("{mtype.ctype} value;")
 -                              self.header.add_decl("\};")
 -                      end
 +              if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
 +                      # Is a primitive type or the Pointer class, not any other extern class
 +
 +                      #Build instance struct
 +                      self.header.add_decl("struct instance_{c_name} \{")
 +                      self.header.add_decl("const struct type *type;")
 +                      self.header.add_decl("const struct class *class;")
 +                      self.header.add_decl("{mtype.ctype_extern} value;")
 +                      self.header.add_decl("\};")
  
 -                      if not rta.live_types.has(mtype) then return
 +                      if not rta.live_types.has(mtype) and mtype.mclass.name != "Pointer" then return
  
                        #Build BOX
 -                      self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
 +                      self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
                        v.add_decl("/* allocate {mtype} */")
 -                      v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
 -                      v.add("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));")
 +                      v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype_extern} value) \{")
 +                      v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
 +                      v.compiler.undead_types.add(mtype)
                        v.require_declaration("type_{c_name}")
                        v.add("res->type = &type_{c_name};")
                        v.require_declaration("class_{c_name}")
                        v.add("res->value = value;")
                        v.add("return (val*)res;")
                        v.add("\}")
 +
 +                      if mtype.mclass.name != "Pointer" then return
 +
 +                      v = new_visitor
 +                      self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
 +                      v.add_decl("/* allocate {mtype} */")
 +                      v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
 +                      if is_dead then
 +                              v.add_abort("{mclass} is DEAD")
 +                      else
 +                              var res = v.new_named_var(mtype, "self")
 +                              res.is_exact = true
 +                              v.add("{res} = nit_alloc(sizeof(struct instance_{mtype.c_name}));")
 +                              v.add("{res}->type = type;")
 +                              hardening_live_type(v, "type")
 +                              v.require_declaration("class_{c_name}")
 +                              v.add("{res}->class = &class_{c_name};")
 +                              v.add("((struct instance_{mtype.c_name}*){res})->value = NULL;")
 +                              v.add("return {res};")
 +                      end
 +                      v.add("\}")
                        return
                else if mclass.name == "NativeArray" then
                        #Build instance struct
 -                      self.header.add_decl("struct instance_{c_instance_name} \{")
 +                      self.header.add_decl("struct instance_{c_name} \{")
                        self.header.add_decl("const struct type *type;")
                        self.header.add_decl("const struct class *class;")
                        # NativeArrays are just a instance header followed by a length and an array of values
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("{mtype.ctype} NEW_{c_name}(int length, const struct type* type) \{")
                        var res = v.get_name("self")
 -                      v.add_decl("struct instance_{c_instance_name} *{res};")
 +                      v.add_decl("struct instance_{c_name} *{res};")
                        var mtype_elt = mtype.arguments.first
 -                      v.add("{res} = nit_alloc(sizeof(struct instance_{c_instance_name}) + length*sizeof({mtype_elt.ctype}));")
 +                      v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("return (val*){res};")
                        v.add("\}")
                        return
 +              else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
 +                      # Is an extern class (other than Pointer and NativeString)
 +                      # Pointer is caught in a previous `if`, and NativeString is internal
 +
 +                      var pointer_type = mainmodule.pointer_type
 +
 +                      self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
 +                      v.add_decl("/* allocate {mtype} */")
 +                      v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
 +                      if is_dead then
 +                              v.add_abort("{mclass} is DEAD")
 +                      else
 +                              var res = v.new_named_var(mtype, "self")
 +                              res.is_exact = true
 +                              v.add("{res} = nit_alloc(sizeof(struct instance_{pointer_type.c_name}));")
 +                              v.add("{res}->type = type;")
 +                              hardening_live_type(v, "type")
 +                              v.require_declaration("class_{c_name}")
 +                              v.add("{res}->class = &class_{c_name};")
 +                              v.add("((struct instance_{pointer_type.c_name}*){res})->value = NULL;")
 +                              v.add("return {res};")
 +                      end
 +                      v.add("\}")
 +                      return
                end
  
                #Build NEW
@@@ -960,22 -909,6 +960,22 @@@ class SeparateCompilerVisito
                end
        end
  
 +      redef fun unbox_signature_extern(m, args)
 +      do
 +              var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
 +              var recv = args.first
 +              if not m.mproperty.is_init and m.is_extern then
 +                      args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type)
 +              end
 +              for i in [0..msignature.arity[ do
 +                      var t = msignature.mparameters[i].mtype
 +                      if i == msignature.vararg_rank then
 +                              t = args[i+1].mtype
 +                      end
 +                      if m.is_extern then args[i+1] = self.unbox_extern(args[i+1], t)
 +              end
 +      end
 +
        redef fun autobox(value, mtype)
        do
                if value.mtype == mtype then
                else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
                        return value
                else if value.mtype.ctype == "val*" then
 -                      return self.new_expr("((struct instance_{mtype.c_instance_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
 +                      return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
                else if mtype.ctype == "val*" then
                        var valtype = value.mtype.as(MClassType)
 +                      if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
 +                              valtype = compiler.mainmodule.pointer_type
 +                      end
                        var res = self.new_var(mtype)
                        if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then
                                self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
                end
        end
  
 +      redef fun unbox_extern(value, mtype)
 +      do
 +              if mtype isa MClassType and mtype.mclass.kind == extern_kind and
 +                 mtype.mclass.name != "NativeString" then
 +                      var pointer_type = compiler.mainmodule.pointer_type
 +                      var res = self.new_var_extern(mtype)
 +                      self.add "{res} = ((struct instance_{pointer_type.c_name}*){value})->value; /* unboxing {value.mtype} */"
 +                      return res
 +              else
 +                      return value
 +              end
 +      end
 +
 +      redef fun box_extern(value, mtype)
 +      do
 +              if mtype isa MClassType and mtype.mclass.kind == extern_kind and
 +                 mtype.mclass.name != "NativeString" then
 +                      var valtype = compiler.mainmodule.pointer_type
 +                      var res = self.new_var(mtype)
 +                      if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
 +                              self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
 +                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                              return res
 +                      end
 +                      self.require_declaration("BOX_{valtype.c_name}")
 +                      self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
 +                      self.require_declaration("type_{mtype.c_name}")
 +                      self.add("{res}->type = &type_{mtype.c_name};")
 +                      self.require_declaration("class_{mtype.c_name}")
 +                      self.add("{res}->class = &class_{mtype.c_name};")
 +                      return res
 +              else
 +                      return value
 +              end
 +      end
 +
        # Return a C expression returning the runtime type structure of the value
        # The point of the method is to works also with primitives types.
        fun type_info(value: RuntimeVariable): String
                                # The attribute is primitive, thus we store it in a box
                                # The trick is to create the box the first time then resuse the box
                                self.add("if ({attr} != NULL) \{")
 -                              self.add("((struct instance_{mtype.c_instance_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
 +                              self.add("((struct instance_{mtype.c_name}*){attr})->value = {value}; /* {a} on {recv.inspect} */")
                                self.add("\} else \{")
                                value = self.autobox(value, self.object_type.as_nullable)
                                self.add("{attr} = {value}; /* {a} on {recv.inspect} */")
                self.add_decl("const char* {res};")
                if value.mtype.ctype == "val*" then
                        self.add "{res} = {value} == NULL ? \"null\" : {value}->type->name;"
 -              else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind then
 +              else if value.mtype isa MClassType and value.mtype.as(MClassType).mclass.kind == extern_kind and
 +                      value.mtype.as(MClassType).name != "NativeString" then
                        self.add "{res} = \"{value.mtype.as(MClassType).mclass}\";"
                else
                        self.require_declaration("type_{value.mtype.c_name}")
                        end
                end
                if primitive != null then
 -                      test.add("((struct instance_{primitive.c_instance_name}*){value1})->value == ((struct instance_{primitive.c_instance_name}*){value2})->value")
 +                      test.add("((struct instance_{primitive.c_name}*){value1})->value == ((struct instance_{primitive.c_name}*){value2})->value")
                else if can_be_primitive(value1) and can_be_primitive(value2) then
                        test.add("{value1}->class == {value2}->class")
                        var s = new Array[String]
                        for t, v in self.compiler.box_kinds do
 -                              s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_instance_name}*){value1})->value == ((struct instance_{t.c_instance_name}*){value2})->value)"
 +                              s.add "({value1}->class->box_kind == {v} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
                        end
                        test.add("({s.join(" || ")})")
                else
        do
                var elttype = arguments.first.mtype
                var nclass = self.get_class("NativeArray")
 -              var recv = "((struct instance_{nclass.c_instance_name}*){arguments[0]})->values"
 +              var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
                if pname == "[]" then
                        self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
                        return
                        self.add("{recv}[{arguments[1]}]={arguments[2]};")
                        return
                else if pname == "length" then
 -                      self.ret(self.new_expr("((struct instance_{nclass.c_instance_name}*){arguments[0]})->length", ret_type.as(not null)))
 +                      self.ret(self.new_expr("((struct instance_{nclass.c_name}*){arguments[0]})->length", ret_type.as(not null)))
                        return
                else if pname == "copy_to" then
 -                      var recv1 = "((struct instance_{nclass.c_instance_name}*){arguments[1]})->values"
 +                      var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
                        self.add("memmove({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
                        return
                end
  
  redef class MType
        fun const_color: String do return "COLOR_{c_name}"
 -
 -      # C name of the instance type to use
 -      fun c_instance_name: String do return c_name
 -end
 -
 -redef class MClassType
 -      redef fun c_instance_name do return mclass.c_instance_name
 -end
 -
 -redef class MClass
 -      # Extern classes use the C instance of kernel::Pointer
 -      fun c_instance_name: String
 -      do
 -              if kind == extern_kind then
 -                      return "kernel__Pointer"
 -              else return c_name
 -      end
  end
  
  interface PropertyLayoutElement end
@@@ -1971,8 -1881,3 +1971,8 @@@ redef class MPropDe
        super PropertyLayoutElement
        fun const_color: String do return "COLOR_{c_name}"
  end
 +
 +redef class AExternInitPropdef
 +      # The semi-global compilation does not support inlining calls to extern news
 +      redef fun can_inline do return false
 +end
@@@ -219,6 -219,7 +219,6 @@@ class SeparateErasureCompile
        do
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 -              var c_instance_name = mclass.c_instance_name
  
                var vft = self.method_tables[mclass]
                var attrs = self.attr_tables[mclass]
                v.add_decl("\}")
                v.add_decl("\};")
  
 -              if mtype.ctype != "val*" then
 -                      if mtype.mclass.name == "Pointer" or mtype.mclass.kind != extern_kind then
 -                              #Build instance struct
 -                              self.header.add_decl("struct instance_{c_instance_name} \{")
 -                              self.header.add_decl("const struct class *class;")
 -                              self.header.add_decl("{mtype.ctype} value;")
 -                              self.header.add_decl("\};")
 -                      end
 +              if mtype.ctype != "val*" or mtype.mclass.name == "Pointer" then
 +                      #Build instance struct
 +                      self.header.add_decl("struct instance_{c_name} \{")
 +                      self.header.add_decl("const struct class *class;")
 +                      self.header.add_decl("{mtype.ctype} value;")
 +                      self.header.add_decl("\};")
  
                        #Build BOX
                        self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
 -                      v.add("struct instance_{c_instance_name}*res = nit_alloc(sizeof(struct instance_{c_instance_name}));")
 +                      v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
                        v.require_declaration("class_{c_name}")
                        v.add("res->class = &class_{c_name};")
                        v.add("res->value = value;")
                        v.add("return (val*)res;")
                        v.add("\}")
 +
 +                      if mtype.mclass.name != "Pointer" then return
 +
 +                      v = new_visitor
 +                      self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}();")
 +                      v.add_decl("/* allocate {mtype} */")
 +                      v.add_decl("{mtype.ctype} NEW_{c_name}() \{")
 +                      if is_dead then
 +                              v.add_abort("{mclass} is DEAD")
 +                      else
 +                              var res = v.new_named_var(mtype, "self")
 +                              res.is_exact = true
 +                              v.add("{res} = nit_alloc(sizeof(struct instance_{mtype.c_name}));")
 +                              v.require_declaration("class_{c_name}")
 +                              v.add("{res}->class = &class_{c_name};")
 +                              v.add("((struct instance_{mtype.c_name}*){res})->value = NULL;")
 +                              v.add("return {res};")
 +                      end
 +                      v.add("\}")
                        return
                else if mclass.name == "NativeArray" then
                        #Build instance struct
                        v.add("return (val*){res};")
                        v.add("\}")
                        return
 +              else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
 +                      var pointer_type = mainmodule.pointer_type
 +
 +                      self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}();")
 +                      v.add_decl("/* allocate {mtype} */")
 +                      v.add_decl("{mtype.ctype} NEW_{c_name}() \{")
 +                      if is_dead then
 +                              v.add_abort("{mclass} is DEAD")
 +                      else
 +                              var res = v.new_named_var(mtype, "self")
 +                              res.is_exact = true
 +                              v.add("{res} = nit_alloc(sizeof(struct instance_{pointer_type.c_name}));")
 +                              #v.add("{res}->type = type;")
 +                              v.require_declaration("class_{c_name}")
 +                              v.add("{res}->class = &class_{c_name};")
 +                              v.add("((struct instance_{pointer_type.c_name}*){res})->value = NULL;")
 +                              v.add("return {res};")
 +                      end
 +                      v.add("\}")
 +                      return
                end
  
                #Build NEW
@@@ -615,40 -579,6 +615,40 @@@ class SeparateErasureCompilerVisito
                return res
        end
  
 +      redef fun unbox_extern(value, mtype)
 +      do
 +              if mtype isa MClassType and mtype.mclass.kind == extern_kind and
 +                 mtype.mclass.name != "NativeString" then
 +                      var pointer_type = compiler.mainmodule.pointer_type
 +                      var res = self.new_var_extern(mtype)
 +                      self.add "{res} = ((struct instance_{pointer_type.c_name}*){value})->value; /* unboxing {value.mtype} */"
 +                      return res
 +              else
 +                      return value
 +              end
 +      end
 +
 +      redef fun box_extern(value, mtype)
 +      do
 +              if mtype isa MClassType and mtype.mclass.kind == extern_kind and
 +                 mtype.mclass.name != "NativeString" then
 +                      var valtype = compiler.mainmodule.pointer_type
 +                      var res = self.new_var(mtype)
 +                      if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
 +                              self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
 +                              self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
 +                              return res
 +                      end
 +                      self.require_declaration("BOX_{valtype.c_name}")
 +                      self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
 +                      self.require_declaration("class_{mtype.c_name}")
 +                      self.add("{res}->class = &class_{mtype.c_name};")
 +                      return res
 +              else
 +                      return value
 +              end
 +      end
 +
        redef fun class_name_string(value)
        do
                var res = self.get_name("var_class_name")
diff --combined src/model/model.nit
@@@ -25,8 -25,6 +25,6 @@@
  # FIXME: better handling of the types
  module model
  
- import poset
- import location
  import mmodule
  import mdoc
  import ordered_tree
@@@ -216,9 -214,6 +214,9 @@@ redef class MModul
  
        private var object_type_cache: nullable MClassType
  
 +      # The type `Pointer`, super class to all extern classes
 +      var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy
 +
        # The primitive type `Bool`
        fun bool_type: MClassType
        do
@@@ -1823,18 -1818,18 +1821,18 @@@ class MMetho
  
        # Is the property defined at the top_level of the module?
        # Currently such a property are stored in `Object`
-       var is_toplevel: Bool writable = false
+       var is_toplevel: Bool = false is writable
  
        # Is the property a constructor?
        # Warning, this property can be inherited by subclasses with or without being a constructor
        # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
-       var is_init: Bool writable = false
+       var is_init: Bool = false is writable
  
        # The constructor is a (the) root init with empty signature but a set of initializers
-       var is_root_init: Bool writable = false
+       var is_root_init: Bool = false is writable
  
        # The the property a 'new' contructor?
-       var is_new: Bool writable = false
+       var is_new: Bool = false is writable
  
        # Is the property a legal constructor for a given class?
        # As usual, visibility is not considered.
@@@ -1949,13 -1944,13 +1947,13 @@@ class MMethodDe
        end
  
        # The signature attached to the property definition
-       var msignature: nullable MSignature writable = null
+       var msignature: nullable MSignature = null is writable
  
        # The signature attached to the `new` call on a root-init
        # This is a concatenation of the signatures of the initializers
        #
        # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
-       var new_msignature: nullable MSignature writable = null
+       var new_msignature: nullable MSignature = null is writable
  
        # List of initialisers to call in root-inits
        #
        var initializers = new Array[MProperty]
  
        # Is the method definition abstract?
-       var is_abstract: Bool writable = false
+       var is_abstract: Bool = false is writable
  
        # Is the method definition intern?
-       var is_intern writable = false
+       var is_intern = false is writable
  
        # Is the method definition extern?
-       var is_extern writable = false
+       var is_extern = false is writable
  end
  
  # A local definition of an attribute
@@@ -1987,7 -1982,7 +1985,7 @@@ class MAttributeDe
        end
  
        # The static type of the attribute
-       var static_mtype: nullable MType writable = null
+       var static_mtype: nullable MType = null is writable
  end
  
  # A local definition of a virtual type
@@@ -2003,10 -1998,10 +2001,10 @@@ class MVirtualTypeDe
        end
  
        # The bound of the virtual type
-       var bound: nullable MType writable = null
+       var bound: nullable MType = null is writable
  
        # Is the bound fixed?
-       var is_fixed writable = false
+       var is_fixed = false is writable
  end
  
  # A kind of class.
diff --combined src/nit.nit
  # A naive Nit interpreter
  module nit
  
- import naive_interpreter
- import debugger
- import debugger_socket
+ import interpreter
+ import frontend
  
  # Create a tool context to handle options and paths
  var toolcontext = new ToolContext
 -toolcontext.tooldescription = "Usage: nit [OPTION]... <file.nit>...\nInterprets and debbugs Nit programs."
 +toolcontext.tooldescription = "Usage: nit [OPTION]... <file.nit>...\nInterprets and debugs Nit programs."
  # Add an option "-o" to enable compatibilit with the tests.sh script
  var opt = new OptionString("compatibility (does noting)", "-o")
  toolcontext.option_context.add_option(opt)
  # It is quite efficient but the type set is global and pollutes each call site.
  module rapid_type_analysis
  
- import model
- import modelbuilder
- import typing
- import auto_super_init
+ import semantize
  
- import csv # for live_types_to_csv
- import ordered_tree # for live_methods_to_tree
+ private import csv # for live_types_to_csv
+ private import ordered_tree # for live_methods_to_tree
  
  private import more_collections
  
@@@ -207,7 -204,6 +204,7 @@@ class RapidTypeAnalysi
                force_alive("Int")
                force_alive("Float")
                force_alive("Char")
 +              force_alive("Pointer")
  
                while not todo.is_empty do
                        var mmethoddef = todo.shift