From: Lucas Bajolet Date: Fri, 17 Jan 2014 22:37:25 +0000 (-0500) Subject: debugger: Modified call chain for calls to runtime injected main methods. X-Git-Tag: v0.6.4~58^2~2 X-Git-Url: http://nitlanguage.org debugger: Modified call chain for calls to runtime injected main methods. Signed-off-by: Lucas Bajolet --- diff --git a/src/debugger.nit b/src/debugger.nit index eea8820..a9e9033 100644 --- a/src/debugger.nit +++ b/src/debugger.nit @@ -241,6 +241,64 @@ class Debugger frame.current_node = old end + # Does the same as an usual send, except it will modify the call chain on the first call when injecting code at Runtime using the debugger. + # Instead of creating a pristine Frame, it will copy the actual values of the frame, and re-inject them after execution in the current context. + fun rt_send(mproperty: MMethod, args: Array[Instance]): nullable Instance + do + var recv = args.first + var mtype = recv.mtype + var ret = send_commons(mproperty, args, mtype) + if ret != null then return ret + var propdef = mproperty.lookup_first_definition(self.mainmodule, mtype) + return self.rt_call(propdef, args) + end + + # Same as a regular call but for a runtime injected module + # + fun rt_call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance + do + args = call_commons(mpropdef, args) + return rt_call_without_varargs(mpropdef, args) + end + + # Common code to call and this function + # + # Call only executes the variadic part, this avoids + # double encapsulation of variadic parameters into an Array + fun rt_call_without_varargs(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance + do + if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then + self.discover_call_trace.add mpropdef + self.debug("Discovered {mpropdef}") + end + if args.length < mpropdef.msignature.arity + 1 or args.length > mpropdef.msignature.arity + 1 then + fatal("NOT YET IMPLEMENTED: Invalid arity for {mpropdef}. {args.length} arguments given.") + end + if args.length < mpropdef.msignature.arity + 1 then + fatal("NOT YET IMPLEMENTED: default closures") + end + + # Look for the AST node that implements the property + var mproperty = mpropdef.mproperty + if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then + var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef] + self.parameter_check(npropdef, mpropdef, args) + if npropdef isa AConcreteMethPropdef then + return npropdef.rt_call(self, mpropdef, args) + else + print "Error, invalid propdef to call at runtime !" + return null + end + else if mproperty.name == "init" then + var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef] + self.parameter_check(nclassdef, mpropdef, args) + return nclassdef.call(self, mpropdef, args) + else + fatal("Fatal Error: method {mpropdef} not found in the AST") + abort + end + end + # Encpasulates the behaviour for step over/out private fun steps_fun_call(n: AExpr) do @@ -1281,7 +1339,35 @@ class Debugger print "untrace variable_name : Removes the trace on the variable you chose to trace earlier in the program" print "kill : kills the current program (Exits with an error and stack trace)\n" end +end +redef class AConcreteMethPropdef + + # Same as call except it will copy local variables of the parent frame to the frame defined in this call. + # Not supposed to be used by anyone else than the Debugger. + private fun rt_call(v: Debugger, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance + do + var f = new Frame(self, self.mpropdef.as(not null), args) + var curr_instances = v.frame.map + for i in curr_instances.keys do + f.map[i] = curr_instances[i] + end + call_commons(v,mpropdef,args,f) + var currFra = v.frames.shift + for i in curr_instances.keys do + if currFra.map.keys.has(i) then + curr_instances[i] = currFra.map[i] + end + end + if v.returnmark == f then + v.returnmark = null + var res = v.escapevalue + v.escapevalue = null + return res + end + return null + + end end # Traces the modifications of an object linked to a certain frame diff --git a/src/naive_interpreter.nit b/src/naive_interpreter.nit index 18981ed..3058bec 100644 --- a/src/naive_interpreter.nit +++ b/src/naive_interpreter.nit @@ -298,10 +298,8 @@ private class NaiveInterpreter # Store known method, used to trace methods as thez are reached var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef] - # Execute `mpropdef` for a `args` (where `args[0]` is the receiver). - # Return a falue if `mpropdef` is a function, or null if it is a procedure. - # The call is direct/static. There is no message-seding/late-binding. - fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance + # Common code for calls to injected methods and normal methods + fun call_commons(mpropdef: MMethodDef, args: Array[Instance]): Array[Instance] do var vararg_rank = mpropdef.msignature.vararg_rank if vararg_rank >= 0 then @@ -328,6 +326,15 @@ private class NaiveInterpreter args.add(rawargs[i+1]) end end + return args + end + + # Execute `mpropdef` for a `args` (where `args[0]` is the receiver). + # Return a falue if `mpropdef` is a function, or null if it is a procedure. + # The call is direct/static. There is no message-seding/late-binding. + fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance + do + args = call_commons(mpropdef, args) return call_without_varargs(mpropdef, args) end @@ -383,13 +390,9 @@ private class NaiveInterpreter end end - # Execute `mproperty` for a `args` (where `args[0]` is the receiver). - # Return a falue if `mproperty` is a function, or null if it is a procedure. - # The call is polimotphic. There is a message-seding/late-bindng according to te receiver (args[0]). - fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance + # Common code for runtime injected calls and normal calls + fun send_commons(mproperty: MMethod, args: Array[Instance], mtype: MType): nullable Instance do - var recv = args.first - var mtype = recv.mtype if mtype isa MNullType then if mproperty.name == "==" then return self.bool_instance(args[0] == args[1]) @@ -398,8 +401,19 @@ private class NaiveInterpreter end #fatal("Reciever is null. {mproperty}. {args.join(" ")} {self.frame.current_node.class_name}") fatal("Reciever is null") - abort end + return null + end + + # Execute `mproperty` for a `args` (where `args[0]` is the receiver). + # Return a falue if `mproperty` is a function, or null if it is a procedure. + # The call is polimotphic. There is a message-seding/late-bindng according to te receiver (args[0]). + fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance + do + var recv = args.first + var mtype = recv.mtype + var ret = send_commons(mproperty, args, mtype) + if ret != null then return ret var propdef = mproperty.lookup_first_definition(self.mainmodule, mtype) return self.call(propdef, args) end @@ -587,9 +601,23 @@ redef class APropdef end redef class AConcreteMethPropdef + redef fun call(v, mpropdef, args) do var f = new Frame(self, self.mpropdef.as(not null), args) + call_commons(v, mpropdef, args, f) + v.frames.shift + if v.returnmark == f then + v.returnmark = null + var res = v.escapevalue + v.escapevalue = null + return res + end + return null + end + + private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance], f: Frame) + do for i in [0..mpropdef.msignature.arity[ do var variable = self.n_signature.n_params[i].variable assert variable != null @@ -612,14 +640,6 @@ redef class AConcreteMethPropdef end v.stmt(self.n_block) - v.frames.shift - if v.returnmark == f then - v.returnmark = null - var res = v.escapevalue - v.escapevalue = null - return res - end - return null end end