From: Alexis Laferrière Date: Wed, 10 Sep 2014 18:54:40 +0000 (-0400) Subject: Merge branch 'master' into polymorphic_extern_classes X-Git-Tag: v0.6.9~38^2~1 X-Git-Url: http://nitlanguage.org?hp=-c Merge branch 'master' into polymorphic_extern_classes --- d4deccd097182290483cc0c7bc69f3ff32cfb6b0 diff --combined lib/pnacl.nit index b997c3f,a76784e..bc876c0 --- a/lib/pnacl.nit +++ b/lib/pnacl.nit @@@ -24,7 -24,16 +24,10 @@@ # Provides PNaCl support for Nit. module pnacl is platform + import standard + intrude import standard::stream + -`{ - #include - #include - #include - #include - #include - #include +in "C Header" `{ #include "ppapi/c/pp_errors.h" #include "ppapi/c/ppp.h" #include "ppapi/c/ppp_instance.h" @@@ -34,15 -43,6 +37,15 @@@ #include "ppapi/c/ppp_messaging.h" #include "ppapi/c/ppb_var_dictionary.h" #include "ppapi/c/ppb_var_array.h" +`} + +`{ + #include + #include + #include + #include + #include + #include #define MAX_DICTIONARY_QUEUE_SIZE 200 #define MAX_MESSAGE_QUEUE_SIZE 10 diff --combined src/compiler/abstract_compiler.nit index 9e67eae,a4c55f8..ef02aec --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@@ -18,10 -18,10 +18,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 @@@ -480,7 -480,7 +480,7 @@@ 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 @@@ -1147,22 -1150,12 +1150,22 @@@ # 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 @@@ -1261,7 -1254,7 +1264,7 @@@ 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 @@@ -1294,16 -1287,6 +1297,16 @@@ 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 @@@ -1332,7 -1315,7 +1335,7 @@@ 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 @@@ -1663,20 -1642,13 +1666,20 @@@ 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 @@@ -1692,6 -1664,8 +1695,6 @@@ 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 @@@ -1896,17 -1882,13 +1911,13 @@@ 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 @@@ -1919,7 -1901,7 +1930,7 @@@ 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 @@@ -1931,244 -1913,246 +1942,247 @@@ 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) @@@ -2177,44 -2161,46 +2191,50 @@@ 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 - diff --combined src/compiler/compiler_ffi.nit index 4c55f65,76e1044..331955e --- a/src/compiler/compiler_ffi.nit +++ b/src/compiler/compiler_ffi.nit @@@ -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) @@@ -144,15 -142,10 +142,10 @@@ 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 @@@ -167,7 -160,6 +160,7 @@@ 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 @@@ -200,24 -192,19 +193,20 @@@ 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 @@@ -227,7 -214,6 +216,7 @@@ var recv_var = v.new_var(return_mtype) v.adapt_signature(mpropdef, arguments) + v.unbox_signature_extern(mpropdef, arguments) arguments.shift @@@ -255,10 -241,10 +244,11 @@@ 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") @@@ -395,14 -381,17 +385,14 @@@ 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) @@@ -410,7 -399,6 +400,7 @@@ 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 @@@ -425,7 -413,6 +415,7 @@@ 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 @@@ -478,8 -463,6 +468,8 @@@ 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") @@@ -507,14 -490,11 +497,14 @@@ 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};") @@@ -541,12 -521,11 +531,12 @@@ 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") @@@ -556,7 -535,6 +546,7 @@@ ## 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) diff --combined src/compiler/global_compiler.nit index 2196071,9a82243..2196071 --- a/src/compiler/global_compiler.nit +++ b/src/compiler/global_compiler.nit @@@ -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 @@@ -199,11 -193,11 +199,11 @@@ 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. @@@ -258,6 -252,7 +258,6 @@@ 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 @@@ -540,7 -507,6 +540,7 @@@ 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 @@@ -553,7 -519,6 +553,7 @@@ 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) @@@ -627,19 -592,6 +627,19 @@@ 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 @@@ -894,15 -846,6 +894,15 @@@ 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 diff --combined src/compiler/separate_compiler.nit index 43d06c2,4dfbeb0..43d06c2 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@@ -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 @@@ -217,11 -213,9 +217,11 @@@ 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] @@@ -668,13 -662,14 +668,13 @@@ 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} */") @@@ -703,24 -698,23 +703,24 @@@ 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}") @@@ -728,31 -722,10 +728,31 @@@ 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 @@@ -765,9 -738,9 +765,9 @@@ 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}") @@@ -776,30 -749,6 +776,30 @@@ 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 @@@ -983,12 -916,9 +983,12 @@@ 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! */") @@@ -1011,42 -941,6 +1011,42 @@@ 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 @@@ -1413,7 -1307,7 +1413,7 @@@ # 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} */") @@@ -1587,8 -1481,7 +1587,8 @@@ 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}") @@@ -1671,12 -1564,12 +1671,12 @@@ 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 @@@ -1742,7 -1635,7 +1742,7 @@@ 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 @@@ -1750,10 -1643,10 +1750,10 @@@ 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 @@@ -1958,6 -1851,23 +1958,6 @@@ en 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 diff --combined src/compiler/separate_erasure_compiler.nit index af3a43c,dcb9d6c..af3a43c --- a/src/compiler/separate_erasure_compiler.nit +++ b/src/compiler/separate_erasure_compiler.nit @@@ -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] @@@ -289,42 -290,25 +289,42 @@@ 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 @@@ -348,26 -332,6 +348,26 @@@ 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 index a0f8c43,765e601..6d5aa9c --- a/src/model/model.nit +++ b/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 # @@@ -1965,13 -1960,13 +1963,13 @@@ 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 index be71611,6e24920..af02fa2 --- a/src/nit.nit +++ b/src/nit.nit @@@ -17,13 -17,12 +17,12 @@@ # 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]... ...\nInterprets and debbugs Nit programs." +toolcontext.tooldescription = "Usage: nit [OPTION]... ...\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) diff --combined src/rapid_type_analysis.nit index 0820839,ea0dcaf..3d8fb9e --- a/src/rapid_type_analysis.nit +++ b/src/rapid_type_analysis.nit @@@ -23,13 -23,10 +23,10 @@@ # 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