rubymirrors 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +7 -0
- data/README.md +30 -0
- data/Rakefile +13 -0
- data/lib/abstract_reflection.rb +112 -0
- data/lib/abstract_reflection/class_mirror.rb +150 -0
- data/lib/abstract_reflection/compiler_mirror.rb +31 -0
- data/lib/abstract_reflection/field_mirror.rb +35 -0
- data/lib/abstract_reflection/gc_mirror.rb +19 -0
- data/lib/abstract_reflection/method_mirror.rb +253 -0
- data/lib/abstract_reflection/mirror.rb +108 -0
- data/lib/abstract_reflection/object_mirror.rb +48 -0
- data/lib/abstract_reflection/stack_frame_mirror.rb +61 -0
- data/lib/abstract_reflection/thread_mirror.rb +64 -0
- data/lib/maglev/reflection.rb +49 -0
- data/lib/maglev/reflection/class_mirror.rb +157 -0
- data/lib/maglev/reflection/core_ext/class_organizer.rb +20 -0
- data/lib/maglev/reflection/core_ext/maglev.rb +5 -0
- data/lib/maglev/reflection/core_ext/method.rb +154 -0
- data/lib/maglev/reflection/core_ext/module.rb +41 -0
- data/lib/maglev/reflection/core_ext/object.rb +4 -0
- data/lib/maglev/reflection/core_ext/thread.rb +226 -0
- data/lib/maglev/reflection/field_mirror.rb +39 -0
- data/lib/maglev/reflection/field_mirror/fixed_instance_variable_mirror.rb +25 -0
- data/lib/maglev/reflection/method_mirror.rb +149 -0
- data/lib/maglev/reflection/mirror.rb +6 -0
- data/lib/maglev/reflection/object_mirror.rb +18 -0
- data/lib/maglev/reflection/stack_frame_mirror.rb +104 -0
- data/lib/maglev/reflection/thread_mirror.rb +116 -0
- data/lib/rubinius/reflection.rb +6 -0
- data/lib/ruby/reflection.rb +74 -0
- data/lib/ruby/reflection/class_mirror.rb +89 -0
- data/lib/ruby/reflection/field_mirror.rb +32 -0
- data/lib/ruby/reflection/field_mirror/class_variable_mirror.rb +25 -0
- data/lib/ruby/reflection/field_mirror/constant_mirror.rb +36 -0
- data/lib/ruby/reflection/field_mirror/instance_variable_mirror.rb +25 -0
- data/lib/ruby/reflection/method_mirror.rb +122 -0
- data/lib/ruby/reflection/mirror.rb +12 -0
- data/lib/ruby/reflection/object_mirror.rb +25 -0
- data/lib/ruby/reflection/stack_frame_mirror.rb +49 -0
- data/lib/ruby/reflection/support/shift_reset.rb +29 -0
- data/lib/ruby/reflection/thread_mirror.rb +47 -0
- data/rubymirrors.gemspec +12 -0
- data/spec/class_spec.rb +92 -0
- data/spec/field_spec.rb +119 -0
- data/spec/fixtures/class_spec.rb +29 -0
- data/spec/fixtures/field_spec.rb +9 -0
- data/spec/fixtures/method_spec.rb +14 -0
- data/spec/fixtures/object_spec.rb +5 -0
- data/spec/fixtures/reflect_spec.rb +14 -0
- data/spec/fixtures/stack_frame_spec.rb +5 -0
- data/spec/fixtures/thread_spec.rb +5 -0
- data/spec/frame_spec.rb +80 -0
- data/spec/method_spec.rb +166 -0
- data/spec/object_spec.rb +18 -0
- data/spec/reflection_spec.rb +74 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/spec_helper/mspec_patch.rb +29 -0
- data/spec/spec_helper/multiple_reflections.rb +14 -0
- data/spec/thread_spec.rb +142 -0
- metadata +173 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'ruby/reflection/field_mirror/class_variable_mirror'
|
2
|
+
require 'ruby/reflection/field_mirror/instance_variable_mirror'
|
3
|
+
require 'ruby/reflection/field_mirror/constant_mirror'
|
4
|
+
require 'maglev/reflection/field_mirror/fixed_instance_variable_mirror'
|
5
|
+
|
6
|
+
module Maglev
|
7
|
+
class Reflection
|
8
|
+
class FieldMirror < Mirror
|
9
|
+
include AbstractReflection::FieldMirror
|
10
|
+
Field = Struct.new(:object, :name)
|
11
|
+
reflect! Field
|
12
|
+
|
13
|
+
def self.mirror_class(field)
|
14
|
+
if reflects?(field)
|
15
|
+
case
|
16
|
+
when field.name.start_with?("@@")
|
17
|
+
Ruby::Reflection::ClassVariableMirror
|
18
|
+
when field.name.start_with?("@")
|
19
|
+
Ruby::Reflection::InstanceVariableMirror
|
20
|
+
when field.name === Symbol
|
21
|
+
FixedInstanceVariableMirror
|
22
|
+
else
|
23
|
+
Ruby::Reflection::ConstantMirror
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(obj)
|
29
|
+
super
|
30
|
+
@object = obj.object
|
31
|
+
@name = obj.name
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
@name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'maglev/reflection/core_ext/module'
|
2
|
+
|
3
|
+
module Maglev
|
4
|
+
class Reflection
|
5
|
+
class FixedInstanceVariableMirror < FieldMirror
|
6
|
+
def initialize(obj)
|
7
|
+
super
|
8
|
+
fixed_ivs = @object.__inst_var_names.to_a
|
9
|
+
@index = index(@name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def public?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def protected?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def private?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'maglev/reflection/core_ext/method'
|
2
|
+
|
3
|
+
module Maglev
|
4
|
+
class Reflection
|
5
|
+
class MethodMirror < Mirror
|
6
|
+
include AbstractReflection::MethodMirror
|
7
|
+
reflect! Method, UnboundMethod, GsNMethod
|
8
|
+
|
9
|
+
# Adding support for on-demand wrapping of GsNMethods
|
10
|
+
def initialize(obj)
|
11
|
+
super
|
12
|
+
if @subject.kind_of? GsNMethod
|
13
|
+
@subject = wrap_gsmeth(@subject)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def file
|
18
|
+
(@subject.source_location || [])[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
def file=(string)
|
22
|
+
raise CapabilitiesExceeded unless regular_method?
|
23
|
+
reload_after do
|
24
|
+
defining_class.reflectee.class_eval(source, string, line)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def line
|
29
|
+
(@subject.source_location || [])[1]
|
30
|
+
end
|
31
|
+
|
32
|
+
def line=(num)
|
33
|
+
raise CapabilitiesExceeded unless regular_method?
|
34
|
+
reload_after do
|
35
|
+
defining_class.reflectee.class_eval(source, file, num)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def source
|
40
|
+
gsmeth.__source_string
|
41
|
+
end
|
42
|
+
|
43
|
+
def source=(str)
|
44
|
+
raise CapabilitiesExceeded unless regular_method?
|
45
|
+
reload_after do
|
46
|
+
if file.nil? && line.nil? # Smalltalk method
|
47
|
+
defining_class.reflectee.__compile_method_category_environment_id(str, '*maglev-dynamic-compile-unclassified', 1)
|
48
|
+
else # Ruby method
|
49
|
+
defining_class.reflectee.class_eval(str, file, line)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def selector
|
55
|
+
@subject.name.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def defining_class
|
59
|
+
reflection.reflect gsmeth.__in_class
|
60
|
+
end
|
61
|
+
|
62
|
+
def arguments
|
63
|
+
gsmeth.__args_and_temps.to_a[0...gsmeth.__num_args].collect(&:to_s)
|
64
|
+
end
|
65
|
+
|
66
|
+
def block_argument
|
67
|
+
return nil unless gsmeth.__selector.to_s[-1] == ?&
|
68
|
+
arguments.last
|
69
|
+
end
|
70
|
+
|
71
|
+
def optional_arguments
|
72
|
+
opt_arg_offset = gsmeth.__ruby_opt_args_bits.to_s(2).reverse.index(?1)
|
73
|
+
argsize = gsmeth.__num_args
|
74
|
+
unless opt_arg_offset
|
75
|
+
if block_argument && splat_argument
|
76
|
+
opt_arg_offset = argsize - 2
|
77
|
+
elsif block_argument || splat_argument
|
78
|
+
opt_arg_offset = argsize - 1
|
79
|
+
else
|
80
|
+
opt_arg_offset = -2
|
81
|
+
end
|
82
|
+
end
|
83
|
+
arguments[opt_arg_offset..-1]
|
84
|
+
end
|
85
|
+
|
86
|
+
def required_arguments
|
87
|
+
arguments - optional_arguments
|
88
|
+
end
|
89
|
+
|
90
|
+
def splat_argument
|
91
|
+
return nil unless gsmeth.__selector.to_s[-2] == ?*
|
92
|
+
block_argument ? arguments[-2] : arguments[-1]
|
93
|
+
end
|
94
|
+
|
95
|
+
def step_offsets
|
96
|
+
gsmeth.__source_offsets
|
97
|
+
end
|
98
|
+
|
99
|
+
def send_offsets
|
100
|
+
offs = gsmeth.__source_offsets_of_sends.to_a
|
101
|
+
offs = offs.each_slice(2).collect do |offset, selector|
|
102
|
+
[prefix_if_ruby_selector(selector), offset]
|
103
|
+
end
|
104
|
+
Hash[*offs.flatten]
|
105
|
+
end
|
106
|
+
|
107
|
+
def bytecodes
|
108
|
+
gsmeth.__ip_steps.to_a.collect {|ip| gsmeth.__opcode_info_at(ip) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def delete
|
112
|
+
raise CapabilitiesExceeded unless regular_method?
|
113
|
+
gsmeth.__in_class.remove_method(selector)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
def wrap_gsmeth(gsmethod)
|
118
|
+
label = gsmethod.__name.to_s
|
119
|
+
cls = gsmethod.__in_class
|
120
|
+
if cls.instance_methods.include?(label)
|
121
|
+
cls.instance_method(label)
|
122
|
+
else
|
123
|
+
GsNMethodWrapper.new(gsmethod)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def gsmeth
|
128
|
+
@subject.__st_gsmeth
|
129
|
+
end
|
130
|
+
|
131
|
+
# Removes the Ruby suffix from the GsNMethod selector
|
132
|
+
def prefix_if_ruby_selector(sym)
|
133
|
+
selector = sym.to_s
|
134
|
+
selector[0...(selector.rindex(?#) || -1)]
|
135
|
+
end
|
136
|
+
|
137
|
+
def regular_method?
|
138
|
+
not (gsmeth.__is_method_for_block || gsmeth.__in_class.nil?)
|
139
|
+
end
|
140
|
+
|
141
|
+
def reload_after(&block)
|
142
|
+
cls = defining_class.reflectee
|
143
|
+
sel = selector.to_sym
|
144
|
+
yield
|
145
|
+
@subject = cls.instance_method(sel)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Maglev
|
2
|
+
class Reflection
|
3
|
+
class ObjectMirror < Ruby::Reflection::ObjectMirror
|
4
|
+
reflect! Object
|
5
|
+
|
6
|
+
private
|
7
|
+
def field_mirrors(list, subject = @subject)
|
8
|
+
list.collect do |name|
|
9
|
+
field_mirror(subject, name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def field_mirror(subject, name)
|
14
|
+
reflection.reflect FieldMirror::Field.new(subject, name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Maglev
|
2
|
+
class Reflection
|
3
|
+
class StackFrameMirror < ObjectMirror
|
4
|
+
include AbstractReflection::StackFrameMirror
|
5
|
+
reflect! ThreadMirror::StackFrame
|
6
|
+
|
7
|
+
attr_reader :method
|
8
|
+
|
9
|
+
def initialize(obj)
|
10
|
+
super
|
11
|
+
@method = obj.method
|
12
|
+
@index = obj.index
|
13
|
+
@thread = obj.thread
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
@method.selector
|
18
|
+
end
|
19
|
+
|
20
|
+
def receiver
|
21
|
+
reflection.reflect detailed_report[1]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self
|
25
|
+
reflection.reflect detailed_report[2]
|
26
|
+
end
|
27
|
+
|
28
|
+
def selector
|
29
|
+
reflection.reflect detailed_report[3].to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def arguments
|
33
|
+
args_and_temps(0, num_args - 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
def locals
|
37
|
+
args_and_temps(num_args, -1)
|
38
|
+
end
|
39
|
+
|
40
|
+
def step_offset
|
41
|
+
detailed_report[4]
|
42
|
+
end
|
43
|
+
|
44
|
+
def source_offset
|
45
|
+
detailed_report[5][step_offset - 1]
|
46
|
+
end
|
47
|
+
|
48
|
+
def variable_context
|
49
|
+
raise NotImplementedError, "TODO"
|
50
|
+
@thread.reflectee.__frame_contents_at(@index)[3]
|
51
|
+
end
|
52
|
+
|
53
|
+
def restart
|
54
|
+
@thread.reflectee.__trim_stack_to_level(@index)
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def pop
|
59
|
+
@thread.reflectee.__trim_stack_to_level(@index + 1)
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def step(*args)
|
64
|
+
@thread.step(*args)
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
"#<#{self.class}: #{@index}: #{@method.defining_class}##{@method.name}>"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
def detailed_report
|
74
|
+
@report ||= @thread.thread_report(@index)
|
75
|
+
end
|
76
|
+
|
77
|
+
def num_args
|
78
|
+
@method.arguments.size
|
79
|
+
end
|
80
|
+
|
81
|
+
def args_and_temps(from, to)
|
82
|
+
names = detailed_report[6][from..to].collect(&:to_s)
|
83
|
+
values = detailed_report[7][from..to].collect(&:to_s)
|
84
|
+
(values.size - names.size).times {|i| names << ".temp#{i+1}"}
|
85
|
+
values.map! {|v| reflection.reflect v }
|
86
|
+
FrameHash[names.zip(values)].tap {|o| o.frame = self }
|
87
|
+
end
|
88
|
+
|
89
|
+
class FrameHash < Hash
|
90
|
+
attr_writer :frame
|
91
|
+
|
92
|
+
def []=(key, value)
|
93
|
+
super
|
94
|
+
if @frame
|
95
|
+
@frame.thread.reflectee.__frame_at_temp_named_put(@frame.index,
|
96
|
+
key.to_s,
|
97
|
+
value)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'maglev/reflection/core_ext/thread'
|
2
|
+
require 'maglev/reflection/core_ext/method'
|
3
|
+
require 'maglev/reflection/core_ext/maglev'
|
4
|
+
require 'maglev/objectlog'
|
5
|
+
|
6
|
+
module Maglev
|
7
|
+
class Reflection
|
8
|
+
class ThreadMirror < Ruby::Reflection::ThreadMirror
|
9
|
+
reflect! Thread
|
10
|
+
StackFrame = Struct.new :method, :index, :thread
|
11
|
+
ExceptionHandlers = {}
|
12
|
+
|
13
|
+
def self.copy_active_thread
|
14
|
+
save_thread("Continuation #{Thread.current}").continuation
|
15
|
+
end
|
16
|
+
|
17
|
+
def stack
|
18
|
+
@subject.__stack_depth.times.collect do |idx|
|
19
|
+
method = reflection.reflect @subject.__method_at(idx + 1)
|
20
|
+
frame = StackFrame.new method, idx + 1, self
|
21
|
+
StackFrameMirror.reflect frame, reflection
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Maglev specific
|
26
|
+
def thread_report(index)
|
27
|
+
@subject.__gsi_debugger_detailed_report_at(index)
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
if @subject.__is_continuation
|
32
|
+
Thread.start { @subject.__value(nil) }.run
|
33
|
+
end
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def wakeup
|
38
|
+
if @subject.__is_continuation
|
39
|
+
raise RuntimeError, "cannot wakeup a continuation with #wakeup"
|
40
|
+
end
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def step(symbol = :over)
|
45
|
+
case symbol
|
46
|
+
when :into
|
47
|
+
@subject.__step_over_in_frame(0)
|
48
|
+
when :over
|
49
|
+
@subject.__step_over_in_frame(1)
|
50
|
+
when :through
|
51
|
+
raise NotImplementedError, "not implemented yet"
|
52
|
+
when Fixnum
|
53
|
+
@subject.__step_over_in_frame(symbol)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def handle_exception(e = Exception, &block)
|
58
|
+
ExceptionHandlers[@subject.object_id] ||= []
|
59
|
+
ExceptionHandlers[@subject.object_id] << proc do |ex|
|
60
|
+
block[ex] if [*e].any? {|ec| ex.is_a? ec }
|
61
|
+
end
|
62
|
+
|
63
|
+
Exception.install_debug_block do |ex|
|
64
|
+
if handlers = ExceptionHandlers[Thread.current.object_id]
|
65
|
+
handlers.each {|h| h[ex] }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Maglev specific... for now
|
71
|
+
def raw_stack
|
72
|
+
stack # Force cache refresh
|
73
|
+
end
|
74
|
+
|
75
|
+
def thread_data
|
76
|
+
@subject.__client_data
|
77
|
+
end
|
78
|
+
|
79
|
+
def compiler_state
|
80
|
+
thread_data.first
|
81
|
+
end
|
82
|
+
|
83
|
+
def shift(block = Proc.new)
|
84
|
+
cm = self.method(:reset).__st_gsmeth
|
85
|
+
markLevel = nil
|
86
|
+
level = 1
|
87
|
+
idx = nil
|
88
|
+
while aFrame = Thread.__frame_contents_at(level) and idx == nil
|
89
|
+
idx = level if aFrame[0] == cm
|
90
|
+
level += 1
|
91
|
+
end
|
92
|
+
raise(RuntimeError, "no enclosing #reset") if idx.nil?
|
93
|
+
# from my caller to the reset caller
|
94
|
+
partial_cc = Thread.__partialContinuationFromLevel_to(2, idx + 1)
|
95
|
+
res = block.call(reflection.reflect(partial_cc))
|
96
|
+
|
97
|
+
# Now, return execution to the reset: call and replace the
|
98
|
+
# top-of-stack with the result of the block
|
99
|
+
|
100
|
+
# from reset to reset caller
|
101
|
+
cc = Thread.__partialContinuationFromLevel_to(idx - 1, idx + 1)
|
102
|
+
Thread.__installPartialContinuation_atLevel_value(cc, idx + 1, res)
|
103
|
+
end
|
104
|
+
|
105
|
+
def reset(block = Proc.new)
|
106
|
+
(proc { block.call }).call
|
107
|
+
end
|
108
|
+
|
109
|
+
def call(arg)
|
110
|
+
if @subject.__is_partial_continuation
|
111
|
+
Thread.__installPartialContinuation_atLevel_value(@subject, 1, arg)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|