4 # Stores information about a running method:
6 # sender:: the MethodContext calling this one
7 # block:: block argument passed in
8 # CompiledMethod:: the method being run
9 # locals:: locals for the callee
10 # defining module:: which module (or class) the CompiledMethod was defined in
11 # receiver:: object this CompiledMethod was sent too.
12 # CPU registers:: VM state for running this CompiledMethod
14 # == Life of a MethodContext
16 # Given a CompiledMethod "m" defined on a module or class K, if the
17 # CompiledMethod has no primitive
19 # When calling a method, a MethodContext "mc" is created if the CompiledMethod
20 # representing the method either has no primitive, or the primitive failed.
22 # mc is filled in with various details from the CompiledMethod. The VM state
23 # is then saved into the active MethodContext and the VM state from mc is
24 # coppied into the VM. The VM will run the CompiledMethod's bytecode until
25 # encountering a return instruction (:ret).
27 # Upon encountering the return instruction, the VM pops off the top of the
28 # stack for use as the return value, restores the previously running
29 # MethodContext's VM state and pushes the return value back onto the stack.
31 # Hey! Be careful with this! This is used by backtrace and if it doesn't work,
32 # you can get recursive exceptions being raised (THATS BAD, BTW).
36 attr_accessor :last_match
43 if method_module.is_a?(MetaClass)
45 "#{method_module.attached_instance.inspect}.#{name}"
47 "#{method_module.attached_instance.class}##{name}"
51 "#{method_module.name}##{name}"
59 if [:__script__, :__block__].include?(self.name)
60 "#{self.file}:#{self.line}"
62 "#{self.file}:#{self.line}:in `#{self.name}'"
66 # The Nth group of the last regexp match.
77 # One of the special globals $&, $`, $' or $+.
99 "#<#{self.class}:0x#{self.object_id.to_s(16)} #{receiver}##{name} #{file}:#{line}>"
101 alias_method :inspect, :to_s
102 # File in which associated method defined.
104 return "(unknown)" unless self.method
108 # See CompiledMethod#lines
110 return [] unless self.method
114 # Current line being executed by the VM.
116 return 0 unless self.method
117 # We subtract 1 because the ip is actually set to what it should do
118 # next, not what it's currently doing (unless we are at the start of
122 self.method.line_from_ip(ip)
126 # Copies context. If locals is true local variable values are also copied
129 def copy(locals=false)
131 return d unless locals
148 # Place in the source that this method was created at.
159 def disable_long_return!
161 # CTX_FLAG_NO_LONG_RETURN => 1
170 # If this context's env was created from a Proc binding
171 # then we duplicate the frame and reset its instruction pointer
172 # in order to show the first line of the block as the active
173 # line in stack trace output
174 if frame.__kind_of__(BlockContext) and frame.env.from_proc?
175 frame = frame.context_from_proc
183 # Get the first IP value in the 'home_block' that is on the
184 # first line of the method representing the Proc and return
185 # a copy of the Proc environment's home block initialized with
187 def context_from_proc
188 frame = self.env.proc_environment.home_block.dup
190 first_line = self.env.proc_environment.method.first_line
191 frame.ip = frame.method.first_ip_on_line(first_line) + 1
196 def stack_trace_starting_at(start=1)
198 trace = self.context_stack
199 return nil if start > trace.size
200 trace.each_with_index do |frame, i|
202 ret << frame.position_info
208 # Desrcibes the execution state of this context. Produces the message you
209 # would see in a backtrace print-out.
212 if method_module.equal?(Kernel)
214 elsif method_module.kind_of?(MetaClass)
216 elsif method_module and method_module != receiver.__class__
217 str = "#{method_module}(#{receiver.__class__})#"
219 str = "#{receiver.__class__}#"
222 if kind_of? BlockContext
224 elsif name == method.name
227 str << "#{name} (#{method.name})"
231 def const_defined?(name)
232 scope = method.staticscope
233 while scope and scope.module != Object
234 return true if scope.module.const_defined?(name)
238 return Object.const_defined?(name)
241 def const_path_defined?(path)
243 return Object.const_path_defined? path[2..-1]
246 parts = path.split("::")
249 scope = method.staticscope
252 mod = top.to_s !~ /self/ ? scope.module.__send__(:recursive_const_get, top, false) : scope.module
253 return mod.const_path_defined? parts.join("::") if mod
258 return Object.const_path_defined? parts.join("::")
261 def class_variable_get(name)
262 return current_scope.class_variable_get(name)
265 def class_variable_set(name, val)
266 return current_scope.class_variable_set(name, val)
269 def class_variable_defined?(name)
270 return current_scope.class_variable_defined?(name)
274 if ss = method.staticscope
282 # Safely dups this MethodContext's method for manipulation.
285 self.method = method.dup
293 # Look up the staticscope chain to find the one with a Script object
294 # attached to it. Return that object.
297 if ss = method.staticscope
298 while ss and !ss.script
302 return ss.script if ss
309 # Used to implement __FILE__ properly. kernel/core/compile.rb stashes
310 # the path used to load this file in the Script object located in
311 # the top staticscope.
314 if script = script_object()
315 if path = script.path
320 # If for some reason that didn't work, return the compile time filename.
325 # Used to set the module body toggles
327 attr_accessor :method_scope
329 def alias_method(name, original)
330 scope = MethodContext.current.sender.current_scope
331 scope.__send__(:alias_method, name, original)
334 # This version is trivial, and is meant to match the API of BlockContext
335 def __const_set__(name, value)
336 const_scope = MethodContext.current.sender.receiver
337 const_scope.__send__(:__const_set__, name, value)
341 # Called when 'def name' is used in userland
343 def __add_method__(name, obj)
344 s = MethodContext.current.sender
345 scope = s.method_scope || :public
347 if name == :initialize or scope == :module
348 visibility = :private
353 # All userland added methods start out with a serial of 1.
356 # Push the scoping down.
357 obj.staticscope = s.method.staticscope
359 Rubinius::VM.reset_method_cache(name)
361 obj.staticscope.module.method_table[name] = Tuple[visibility, obj]
364 s.current_scope.module_function name
367 if s.current_scope.respond_to? :method_added
368 s.current_scope.method_added(name)
371 # Return value here is the return value of the 'def' expression
378 # Stores all the information about a running NativeMethod.
380 class NativeMethodContext