Merge branch 'use_more_callsite'
authorJean Privat <jean@pryen.org>
Mon, 24 Feb 2014 15:55:20 +0000 (10:55 -0500)
committerJean Privat <jean@pryen.org>
Mon, 24 Feb 2014 15:55:20 +0000 (10:55 -0500)
CallSite is a great data-class to store various information on a call
site.

This series generalizes its usage in some place, and remove a old
depreciated API.

This uniformization and cleanup will be useful in future work, like
call-site optimizations and the new constructors

1  2 
src/abstract_compiler.nit
src/naive_interpreter.nit
src/typing.nit

@@@ -21,7 -21,6 +21,7 @@@ import litera
  import typing
  import auto_super_init
  import frontend
 +import common_ffi
  
  # Add compiling options
  redef class ToolContext
@@@ -107,14 -106,8 +107,14 @@@ redef class ModelBuilde
                        cc_paths.append(path_env.split_with(':'))
                end
  
 +              var compile_dir = toolcontext.opt_compile_dir.value
 +              if compile_dir == null then compile_dir = ".nit_compile"
 +              self.compile_dir = compile_dir
        end
  
 +      # The compilation directory
 +      var compile_dir: String
 +
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var mainmodule = compiler.mainmodule
                var time0 = get_time
                self.toolcontext.info("*** WRITING C ***", 1)
  
 -              var compile_dir = toolcontext.opt_compile_dir.value
 -              if compile_dir == null then compile_dir = ".nit_compile"
 -
                compile_dir.mkdir
  
                if self.toolcontext.opt_stacktrace.value then compiler.build_c_to_nit_bindings
  
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
  
 +              # FFI
 +              for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
 +                      var amodule = mmodule2nmodule[m]
 +                      if m.uses_ffi or amodule.uses_legacy_ni then
 +                              compiler.finalize_ffi_for_module(amodule)
 +                      end
 +              end
 +
                # Generate the Makefile
  
                var makename = "{mainmodule.name}.mk"
                        p = orig_dir.join_path(p).simplify_path
                        cc_includes += " -I \"" + p + "\""
                end
 -              if toolcontext.opt_no_stacktrace.value then
 -                      makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS  ?= -lm -lgc\n\n")
 -              else
 -                      makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS  ?= -lunwind -lm -lgc\n\n")
 +
 +              var linker_options = new HashSet[String]
 +              for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
 +                      var amod = mmodule2nmodule[m]
 +                      linker_options.add(amod.c_linker_options)
                end
 +
 +              if not toolcontext.opt_no_stacktrace.value then
 +                      linker_options.add("-lunwind")
 +    end
 +
 +              makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS  ?= -lm -lgc {linker_options.join(" ")}\n\n")
                makefile.write("all: {outpath}\n\n")
  
                var ofiles = new Array[String]
  
                # Compile each required extern body into a specific .o
                for f in compiler.extern_bodies do
 -                      var basename = f.filename.basename(".c")
 -                      var o = "{basename}.extern.o"
 -                      var ff = orig_dir.join_path(f.filename).simplify_path
 -                      makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
 -                      ofiles.add(o)
 +                      if f isa ExternCFile then
 +                              var basename = f.filename.basename(".c")
 +                              var o = "{basename}.extern.o"
 +                              var ff = orig_dir.join_path(f.filename).simplify_path
 +                              makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
 +                              ofiles.add(o)
 +                      end
                end
  
                # Link edition
@@@ -352,7 -331,8 +352,7 @@@ abstract class AbstractCompile
        # Binds the generated C function names to Nit function names
        fun build_c_to_nit_bindings
        do
 -              var compile_dir = modelbuilder.toolcontext.opt_compile_dir.value
 -              if compile_dir == null then compile_dir = ".nit_compile"
 +              var compile_dir = modelbuilder.compile_dir
  
                var stream = new OFStream.open("{compile_dir}/C_fun_names")
                stream.write("%\{\n#include \"c_functions_hash.h\"\n%\}\n")
                self.header.add_decl("#include <gc_chooser.h>")
  
                compile_header_structs
 +              compile_nitni_structs
  
                # Signal handler function prototype
                self.header.add_decl("void show_backtrace(int);")
  
 -              # Global variable used by the legacy native interface
 +              # Global variable used by intern methods
                self.header.add_decl("extern int glob_argc;")
                self.header.add_decl("extern char **glob_argv;")
                self.header.add_decl("extern val *glob_sys;")
        end
  
 -      # Declaration of structures the live Nit types
 +      # Declaration of structures for live Nit types
        protected fun compile_header_structs is abstract
  
 +      # Declaration of structures for nitni undelying the FFI
 +      protected fun compile_nitni_structs is abstract
 +
        # Generate the main C function.
        # This function:
        #       * allocate the Sys object if it exists
                v.add("\}")
        end
  
 -      # List of additional .c files required to compile (native interface)
 -      var extern_bodies = new Array[ExternCFile]
 +      # List of additional files required to compile (FFI)
 +      var extern_bodies = new Array[ExternFile]
  
        # This is used to avoid adding an extern file more than once
        private var seen_extern = new ArraySet[String]
                if b == 0 then return "n/a"
                return ((a*10000/b).to_f / 100.0).to_precision(2)
        end
 +
 +      fun finalize_ffi_for_module(nmodule: AModule)
 +      do
 +              var visitor = new_visitor
 +              nmodule.finalize_ffi(visitor, modelbuilder)
 +              nmodule.finalize_nitni(visitor)
 +      end
 +
 +      # Does this compiler support the FFI?
 +      fun supports_ffi: Bool do return false
  end
  
  # A file unit (may be more than one file if
@@@ -1226,6 -1192,14 +1226,6 @@@ class Fram
        var returnlabel: nullable String writable = null
  end
  
 -# An extern C file to compile
 -class ExternCFile
 -      # The filename of the file
 -      var filename: String
 -      # Additionnal specific CC compiler -c flags
 -      var cflags: String
 -end
 -
  redef class MType
        # Return the C type associated to a given Nit static type
        fun ctype: String do return "val*"
@@@ -2402,13 -2376,13 +2402,13 @@@ redef class ASuperExp
                        args = v.frame.arguments
                end
  
-               var mproperty = self.mproperty
-               if mproperty != null then
-                       if mproperty.intro.msignature.arity == 0 then
+               var callsite = self.callsite
+               if callsite != null then
+                       if callsite.mproperty.intro.msignature.arity == 0 then
                                args = [recv]
                        end
                        # Super init call
-                       var res = v.send(mproperty, args)
+                       var res = v.compile_callsite(callsite, args)
                        return res
                end
  
@@@ -2526,14 -2500,3 +2526,14 @@@ redef class MModul
        end
        private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
  end
 +
 +redef class AModule
 +      # Does this module use the legacy native interface?
 +      fun uses_legacy_ni: Bool is abstract
 +
 +      # Write FFI results to file
 +      fun finalize_ffi(v: AbstractCompilerVisitor, modelbuilder: ModelBuilder) is abstract
 +
 +      # Write nitni results to file
 +      fun finalize_nitni(v: AbstractCompilerVisitor) is abstract
 +end
@@@ -751,13 -751,13 +751,13 @@@ redef class AInternMethPropde
                                if arg1 >= recvval.length or arg1 < 0 then
                                        debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
                                end
 -                              return v.char_instance(recvval[arg1])
 +                              return v.char_instance(recvval.chars[arg1])
                        else if pname == "[]=" then
                                var arg1 = args[1].to_i
                                if arg1 >= recvval.length or arg1 < 0 then
                                        debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
                                end
 -                              recvval[arg1] = args[2].val.as(Char)
 +                              recvval.chars[arg1] = args[2].val.as(Char)
                                return null
                        else if pname == "copy_to" then
                                # sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
@@@ -1103,7 -1103,7 +1103,7 @@@ redef class AVarReassignExp
                var vari = v.frame.map[self.variable.as(not null)]
                var value = v.expr(self.n_value)
                if value == null then return
-               var res = v.send(reassign_property.mproperty, [vari, value])
+               var res = v.send(reassign_callsite.mproperty, [vari, value])
                assert res != null
                v.frame.map[self.variable.as(not null)] = res
        end
@@@ -1517,9 -1517,8 +1517,8 @@@ redef class ASendExp
                        if i == null then return null
                        args.add(i)
                end
-               var mproperty = self.mproperty.as(not null)
  
-               var res = v.send(mproperty, args)
+               var res = v.send(callsite.mproperty, args)
                return res
        end
  end
@@@ -1538,16 -1537,15 +1537,15 @@@ redef class ASendReassignFormExp
                var value = v.expr(self.n_value)
                if value == null then return
  
-               var mproperty = self.mproperty.as(not null)
-               var read = v.send(mproperty, args)
+               var read = v.send(callsite.mproperty, args)
                assert read != null
  
-               var write = v.send(self.reassign_property.mproperty, [read, value])
+               var write = v.send(reassign_callsite.mproperty, [read, value])
                assert write != null
  
                args.add(write)
  
-               v.send(self.write_mproperty.as(not null), args)
+               v.send(write_callsite.mproperty, args)
        end
  end
  
@@@ -1565,13 -1563,13 +1563,13 @@@ redef class ASuperExp
                        args = v.frame.arguments
                end
  
-               var mproperty = self.mproperty
-               if mproperty != null then
-                       if mproperty.intro.msignature.arity == 0 then
+               var callsite = self.callsite
+               if callsite != null then
+                       if callsite.mproperty.intro.msignature.arity == 0 then
                                args = [recv]
                        end
                        # Super init call
-                       var res = v.send(mproperty, args)
+                       var res = v.send(callsite.mproperty, args)
                        return res
                end
  
@@@ -1596,8 -1594,7 +1594,7 @@@ redef class ANewExp
                        if i == null then return null
                        args.add(i)
                end
-               var mproperty = self.mproperty.as(not null)
-               var res2 = v.send(mproperty, args)
+               var res2 = v.send(callsite.mproperty, args)
                if res2 != null then
                        #self.debug("got {res2} from {mproperty}. drop {recv}")
                        return res2
@@@ -1641,7 -1638,7 +1638,7 @@@ redef class AAttrReassignExp
                if value == null then return
                var mproperty = self.mproperty.as(not null)
                var attr = v.read_attribute(mproperty, recv)
-               var res = v.send(reassign_property.mproperty, [attr, value])
+               var res = v.send(reassign_callsite.mproperty, [attr, value])
                assert res != null
                assert recv isa MutableInstance
                recv.attributes[mproperty] = res
diff --combined src/typing.nit
@@@ -640,9 -640,6 +640,6 @@@ redef class AVarAssignExp
  end
  
  redef class AReassignFormExpr
-       # @depreciated use `reassign_callsite`
-       fun reassign_property: nullable MMethodDef do return self.reassign_callsite.mpropdef
        # The method designed by the reassign operator.
        var reassign_callsite: nullable CallSite
  
@@@ -1190,9 -1187,6 +1187,6 @@@ en
  ## MESSAGE SENDING AND PROPERTY
  
  redef class ASendExpr
-       # @depreciated: use `callsite`
-       fun mproperty: nullable MMethod do return callsite.mproperty
        # The property invoked by the send.
        var callsite: nullable CallSite
  
@@@ -1353,9 -1347,6 +1347,6 @@@ redef class ABraAssignExp
  end
  
  redef class ASendReassignFormExpr
-       # @depreciated use `write_callsite`
-       fun write_mproperty: nullable MMethod do return write_callsite.mproperty
        # The property invoked for the writing
        var write_callsite: nullable CallSite
  
@@@ -1426,7 -1417,7 +1417,7 @@@ en
  redef class ASuperExpr
        # The method to call if the super is in fact a 'super init call'
        # Note: if the super is a normal call-next-method, then this attribute is null
-       var mproperty: nullable MMethod
+       var callsite: nullable CallSite
  
        redef fun accept_typing(v)
        do
                end
                # FIXME: covariance of return type in linear extension?
                var superprop = superprops.first
 -              assert superprop isa MMethodDef
  
                var msignature = v.resolve_signature_for(superprop, recvtype, true)
                var args = self.n_args.to_a
                        v.error(self, "Error: No super method to call for {mproperty}.")
                        return
                end
-               self.mproperty = superprop.mproperty
  
-               var args = self.n_args.to_a
                var msignature = v.resolve_signature_for(superprop, recvtype, true)
+               var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
+               self.callsite = callsite
+               var args = self.n_args.to_a
                if args.length > 0 then
-                       v.check_signature(self, args, mproperty.name, msignature)
+                       callsite.check_signature(v, args)
                else
                        # TODO: Check signature
                end
@@@ -1507,9 -1501,6 +1500,6 @@@ en
  ####
  
  redef class ANewExpr
-       # @depreciated use `callsite`
-       fun mproperty: nullable MMethod do return self.callsite.mproperty
        # The constructor invoked by the new.
        var callsite: nullable CallSite