rubinius-compiler 1.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.
@@ -0,0 +1,146 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ ##
4
+ # Defines all the bytecode instructions used by the VM.
5
+
6
+ module Rubinius
7
+ class InstructionSet
8
+
9
+ class OpCode
10
+ attr_reader :args, :arg_count, :bytecode, :opcode, :size,
11
+ :stack, :stack_consumed, :stack_produced, :variable_stack,
12
+ :position, :produced_position, :stack_difference, :control_flow
13
+
14
+ alias_method :name, :opcode
15
+ alias_method :width, :size
16
+
17
+ def initialize(opcode, bytecode, params)
18
+ @opcode = opcode
19
+ @bytecode = bytecode
20
+ @args = params[:args]
21
+ @arg_count = @args.size
22
+ @size = @arg_count + 1
23
+ @position = nil
24
+ @produced_position = nil
25
+
26
+ @stack_consumed, @stack_produced = params[:stack]
27
+ if @stack_consumed.kind_of? Fixnum
28
+ if @stack_produced.kind_of? Fixnum
29
+ @variable_stack = false
30
+ @stack_difference = @stack_produced - @stack_consumed
31
+ else
32
+ @variable_stack = true
33
+ produced_extra, @produced_position, @produced_times = @stack_produced
34
+ @stack_difference = produced_extra - @stack_consumed
35
+ end
36
+ else
37
+ @variable_stack = true
38
+ extra, @position = @stack_consumed
39
+
40
+ if @stack_produced.kind_of? Fixnum
41
+ @stack_difference = @stack_produced - extra
42
+ else
43
+ produced_extra, @produced_position, @produced_times = @stack_produced
44
+ @stack_difference = produced_extra - extra
45
+ end
46
+ end
47
+
48
+ @control_flow = params[:control_flow]
49
+ end
50
+
51
+ def variable_stack?
52
+ @variable_stack
53
+ end
54
+
55
+ def to_s
56
+ @opcode.to_s
57
+ end
58
+ end
59
+
60
+
61
+ # InstructionSet methods
62
+
63
+ # Returns the opcode map.
64
+ def self.opcodes_map
65
+ @opcodes_map ||= Rubinius::LookupTable.new
66
+ end
67
+
68
+ # Returns an array of OpCode instances.
69
+ def self.opcodes
70
+ @opcodes ||= []
71
+ end
72
+
73
+ # Utility method for defining the opcodes.
74
+ def self.opcode(id, name, params={})
75
+ opcodes[id] = OpCode.new name, id, params
76
+ opcodes_map[name] = opcodes_map[id] = id
77
+ end
78
+
79
+ class InvalidOpCode < RuntimeError
80
+ end
81
+
82
+ # Returns an opcode given its name or numeric ID.
83
+ def self.[](name_or_id)
84
+ opcode = opcodes[opcodes_map[name_or_id]]
85
+ raise InvalidOpCode, "Invalid opcode #{op.inspect}" unless opcode
86
+ opcode
87
+ end
88
+ end
89
+
90
+ ##
91
+ # Aids in decoding an instruction sequence into information
92
+ # about each instruction
93
+ #
94
+ class InstructionDecoder
95
+ def initialize(iseq)
96
+ @iseq = iseq
97
+ end
98
+
99
+ ##
100
+ # Decodes an InstructionSequence (which is essentially a an array of ints)
101
+ # into an array whose elements are arrays of opcode symbols and 0-2 args,
102
+ # depending on the opcode.
103
+
104
+ def decode(symbols=false)
105
+ stream = decode_between(0, @iseq.size)
106
+
107
+ if symbols
108
+ stream.each { |i| i[0] = i[0].opcode }
109
+ end
110
+
111
+ return stream
112
+ end
113
+
114
+ def decode_between(start, fin)
115
+ offset = start
116
+
117
+ stream = []
118
+
119
+ while offset < fin
120
+ inst = @iseq[offset]
121
+ op = InstructionSet[inst]
122
+
123
+ case op.arg_count
124
+ when 0
125
+ stream << [op]
126
+ when 1
127
+ stream << [op, @iseq[offset+1]]
128
+ when 2
129
+ stream << [op, @iseq[offset+1], @iseq[offset+2]]
130
+ end
131
+
132
+ offset += op.width
133
+ end
134
+
135
+ return stream
136
+ end
137
+
138
+ def show
139
+ ip = 0
140
+ decode.each do |inst|
141
+ puts "%4s: %s" % [ip, inst.join(" ")]
142
+ ip += inst.size
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,147 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ class Compiler
5
+ module LocalVariables
6
+ def variables
7
+ @variables ||= {}
8
+ end
9
+
10
+ def local_count
11
+ variables.size
12
+ end
13
+
14
+ def local_names
15
+ names = []
16
+ eval_names = []
17
+ variables.each_pair do |name, var|
18
+ case var
19
+ when EvalLocalVariable
20
+ eval_names << name
21
+ when LocalVariable
22
+ names[var.slot] = name
23
+ # We ignore NestedLocalVariables because they're
24
+ # tagged as existing only in their source scope.
25
+ end
26
+ end
27
+ names += eval_names
28
+ end
29
+
30
+ def allocate_slot
31
+ variables.size
32
+ end
33
+ end
34
+
35
+ class LocalVariable
36
+ attr_reader :slot
37
+
38
+ def initialize(slot)
39
+ @slot = slot
40
+ end
41
+
42
+ def reference
43
+ LocalReference.new @slot
44
+ end
45
+
46
+ def nested_reference
47
+ NestedLocalReference.new @slot
48
+ end
49
+ end
50
+
51
+ class NestedLocalVariable
52
+ attr_reader :depth, :slot
53
+
54
+ def initialize(depth, slot)
55
+ @depth = depth
56
+ @slot = slot
57
+ end
58
+
59
+ def reference
60
+ NestedLocalReference.new @slot, @depth
61
+ end
62
+
63
+ alias_method :nested_reference, :reference
64
+ end
65
+
66
+ class EvalLocalVariable
67
+ attr_reader :name
68
+
69
+ def initialize(name)
70
+ @name = name
71
+ end
72
+
73
+ def reference
74
+ EvalLocalReference.new @name
75
+ end
76
+
77
+ alias_method :nested_reference, :reference
78
+ end
79
+
80
+ class LocalReference
81
+ attr_reader :slot
82
+
83
+ def initialize(slot)
84
+ @slot = slot
85
+ end
86
+
87
+ def get_bytecode(g)
88
+ g.push_local @slot
89
+ end
90
+
91
+ def set_bytecode(g)
92
+ g.set_local @slot
93
+ end
94
+ end
95
+
96
+ class NestedLocalReference
97
+ attr_accessor :depth
98
+ attr_reader :slot
99
+
100
+ def initialize(slot, depth=0)
101
+ @slot = slot
102
+ @depth = depth
103
+ end
104
+
105
+ def get_bytecode(g)
106
+ if @depth == 0
107
+ g.push_local @slot
108
+ else
109
+ g.push_local_depth @depth, @slot
110
+ end
111
+ end
112
+
113
+ def set_bytecode(g)
114
+ if @depth == 0
115
+ g.set_local @slot
116
+ else
117
+ g.set_local_depth @depth, @slot
118
+ end
119
+ end
120
+ end
121
+
122
+ class EvalLocalReference
123
+
124
+ # Ignored, but simplifies duck-typing references
125
+ attr_accessor :depth
126
+
127
+ def initialize(name)
128
+ @name = name
129
+ @depth = 0
130
+ end
131
+
132
+ def get_bytecode(g)
133
+ g.push_variables
134
+ g.push_literal @name
135
+ g.send :get_eval_local, 1, false
136
+ end
137
+
138
+ def set_bytecode(g)
139
+ g.push_variables
140
+ g.swap
141
+ g.push_literal @name
142
+ g.swap
143
+ g.send :set_eval_local, 2, false
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,150 @@
1
+ # *** This file is generated by InstructionParser ***
2
+
3
+ module Rubinius
4
+ class InstructionSet
5
+ opcode 0, :noop, :stack => [0, 0], :args => [], :control_flow => :next
6
+
7
+ # Push primitive values
8
+ opcode 1, :push_nil, :stack => [0, 1], :args => [], :control_flow => :next
9
+ opcode 2, :push_true, :stack => [0, 1], :args => [], :control_flow => :next
10
+ opcode 3, :push_false, :stack => [0, 1], :args => [], :control_flow => :next
11
+ opcode 4, :push_int, :stack => [0, 1], :args => [:number], :control_flow => :next
12
+ opcode 5, :push_self, :stack => [0, 1], :args => [], :control_flow => :next
13
+
14
+ # Manipulate literals
15
+ opcode 6, :set_literal, :stack => [1, 1], :args => [:literal], :control_flow => :next
16
+ opcode 7, :push_literal, :stack => [0, 1], :args => [:literal], :control_flow => :next
17
+
18
+ # Flow control
19
+ opcode 8, :goto, :stack => [0, 0], :args => [:location], :control_flow => :branch
20
+ opcode 9, :goto_if_false, :stack => [1, 0], :args => [:location], :control_flow => :branch
21
+ opcode 10, :goto_if_true, :stack => [1, 0], :args => [:location], :control_flow => :branch
22
+ opcode 11, :ret, :stack => [1, 1], :args => [], :control_flow => :return
23
+
24
+ # Stack manipulations
25
+ opcode 12, :swap_stack, :stack => [2, 2], :args => [], :control_flow => :next
26
+ opcode 13, :dup_top, :stack => [1, 2], :args => [], :control_flow => :next
27
+ opcode 14, :dup_many, :stack => [[0,1], [0, 1, 2]],:args => [:count], :control_flow => :next
28
+ opcode 15, :pop, :stack => [1, 0], :args => [], :control_flow => :next
29
+ opcode 16, :pop_many, :stack => [[0,1], 0], :args => [:count], :control_flow => :next
30
+ opcode 17, :rotate, :stack => [[0,1], [0, 1, 1]],:args => [:count], :control_flow => :next
31
+ opcode 18, :move_down, :stack => [[0,1], [0, 1, 1]],:args => [:positions], :control_flow => :next
32
+
33
+ # Manipulate local variables
34
+ opcode 19, :set_local, :stack => [1, 1], :args => [:local], :control_flow => :next
35
+ opcode 20, :push_local, :stack => [0, 1], :args => [:local], :control_flow => :next
36
+ opcode 21, :push_local_depth, :stack => [0, 1], :args => [:depth, :index], :control_flow => :next
37
+ opcode 22, :set_local_depth, :stack => [1, 1], :args => [:depth, :index], :control_flow => :next
38
+ opcode 23, :passed_arg, :stack => [0, 1], :args => [:index], :control_flow => :next
39
+
40
+ # Manipulate exceptions
41
+ opcode 24, :push_current_exception, :stack => [0, 1], :args => [], :control_flow => :next
42
+ opcode 25, :clear_exception, :stack => [0, 0], :args => [], :control_flow => :next
43
+ opcode 26, :push_exception_state, :stack => [0, 1], :args => [], :control_flow => :next
44
+ opcode 27, :restore_exception_state, :stack => [1, 0], :args => [], :control_flow => :next
45
+ opcode 28, :raise_exc, :stack => [1, 0], :args => [], :control_flow => :raise
46
+ opcode 29, :setup_unwind, :stack => [0, 0], :args => [:ip, :type], :control_flow => :handler
47
+ opcode 30, :pop_unwind, :stack => [0, 0], :args => [], :control_flow => :next
48
+ opcode 31, :raise_return, :stack => [1, 1], :args => [], :control_flow => :raise
49
+ opcode 32, :ensure_return, :stack => [1, 1], :args => [], :control_flow => :raise
50
+ opcode 33, :raise_break, :stack => [1, 1], :args => [], :control_flow => :raise
51
+ opcode 34, :reraise, :stack => [0, 0], :args => [], :control_flow => :raise
52
+
53
+ # Manipulate arrays
54
+ opcode 35, :make_array, :stack => [[0,1], 1], :args => [:count], :control_flow => :next
55
+ opcode 36, :cast_array, :stack => [1, 1], :args => [], :control_flow => :next
56
+ opcode 37, :shift_array, :stack => [1, 2], :args => [], :control_flow => :next
57
+
58
+ # Manipulate instance variables
59
+ opcode 38, :set_ivar, :stack => [1, 1], :args => [:literal], :control_flow => :next
60
+ opcode 39, :push_ivar, :stack => [0, 1], :args => [:literal], :control_flow => :next
61
+
62
+ # Manipulate constants
63
+ opcode 40, :push_const, :stack => [0, 1], :args => [:literal], :control_flow => :next
64
+ opcode 41, :set_const, :stack => [1, 1], :args => [:literal], :control_flow => :next
65
+ opcode 42, :set_const_at, :stack => [2, 1], :args => [:literal], :control_flow => :next
66
+ opcode 43, :find_const, :stack => [1, 1], :args => [:literal], :control_flow => :next
67
+ opcode 44, :push_cpath_top, :stack => [0, 1], :args => [], :control_flow => :next
68
+ opcode 45, :push_const_fast, :stack => [0, 1], :args => [:literal], :control_flow => :next
69
+ opcode 46, :find_const_fast, :stack => [1, 1], :args => [:literal], :control_flow => :next
70
+
71
+ # Send messages
72
+ opcode 47, :set_call_flags, :stack => [0, 0], :args => [:flags], :control_flow => :next
73
+ opcode 48, :allow_private, :stack => [0, 0], :args => [], :control_flow => :next
74
+ opcode 49, :send_method, :stack => [1, 1], :args => [:literal], :control_flow => :send
75
+ opcode 50, :send_stack, :stack => [[1,2], 1], :args => [:literal, :count], :control_flow => :send
76
+ opcode 51, :send_stack_with_block, :stack => [[2,2], 1], :args => [:literal, :count], :control_flow => :send
77
+
78
+ CALL_FLAG_CONCAT = 2
79
+
80
+ opcode 52, :send_stack_with_splat, :stack => [[3,2], 1], :args => [:literal, :count], :control_flow => :send
81
+ opcode 53, :send_super_stack_with_block, :stack => [[1,2], 1], :args => [:literal, :count], :control_flow => :send
82
+ opcode 54, :send_super_stack_with_splat, :stack => [[2,2], 1], :args => [:literal, :count], :control_flow => :send
83
+
84
+ # Manipulate blocks
85
+ opcode 55, :push_block, :stack => [0, 1], :args => [], :control_flow => :next
86
+ opcode 56, :passed_blockarg, :stack => [0, 1], :args => [:count], :control_flow => :next
87
+ opcode 57, :create_block, :stack => [0, 1], :args => [:literal], :control_flow => :next
88
+ opcode 58, :cast_for_single_block_arg, :stack => [0, 1], :args => [], :control_flow => :next
89
+ opcode 59, :cast_for_multi_block_arg, :stack => [0, 1], :args => [], :control_flow => :next
90
+ opcode 60, :cast_for_splat_block_arg, :stack => [0, 1], :args => [], :control_flow => :next
91
+ opcode 61, :yield_stack, :stack => [[0,1], 1], :args => [:count], :control_flow => :yield
92
+ opcode 62, :yield_splat, :stack => [[1,1], 1], :args => [:count], :control_flow => :yield
93
+
94
+ # Manipulate strings
95
+ opcode 63, :string_append, :stack => [2, 1], :args => [], :control_flow => :next
96
+ opcode 64, :string_build, :stack => [[0,1], 1], :args => [:count], :control_flow => :next
97
+ opcode 65, :string_dup, :stack => [1, 1], :args => [], :control_flow => :next
98
+
99
+ # Manipulate scope
100
+ opcode 66, :push_scope, :stack => [0, 1], :args => [], :control_flow => :next
101
+ opcode 67, :add_scope, :stack => [1, 0], :args => [], :control_flow => :next
102
+ opcode 68, :push_variables, :stack => [0, 1], :args => [], :control_flow => :next
103
+
104
+ # Miscellaneous. TODO: better categorize these
105
+ opcode 69, :check_interrupts, :stack => [0, 0], :args => [], :control_flow => :next
106
+ opcode 70, :yield_debugger, :stack => [0, 0], :args => [], :control_flow => :next
107
+ opcode 71, :is_nil, :stack => [1, 1], :args => [], :control_flow => :next
108
+ opcode 72, :check_serial, :stack => [1, 1], :args => [:literal, :serial], :control_flow => :next
109
+ opcode 73, :check_serial_private, :stack => [1, 1], :args => [:literal, :serial], :control_flow => :next
110
+
111
+ # Access object fields
112
+ opcode 74, :push_my_field, :stack => [0, 1], :args => [:index], :control_flow => :next
113
+ opcode 75, :store_my_field, :stack => [1, 1], :args => [:index], :control_flow => :next
114
+
115
+ # Type checks
116
+ opcode 76, :kind_of, :stack => [2, 1], :args => [], :control_flow => :next
117
+ opcode 77, :instance_of, :stack => [2, 1], :args => [], :control_flow => :next
118
+
119
+ # Optimizations
120
+ opcode 78, :meta_push_neg_1, :stack => [0, 1], :args => [], :control_flow => :next
121
+ opcode 79, :meta_push_0, :stack => [0, 1], :args => [], :control_flow => :next
122
+ opcode 80, :meta_push_1, :stack => [0, 1], :args => [], :control_flow => :next
123
+ opcode 81, :meta_push_2, :stack => [0, 1], :args => [], :control_flow => :next
124
+ opcode 82, :meta_send_op_plus, :stack => [2, 1], :args => [:literal], :control_flow => :send
125
+ opcode 83, :meta_send_op_minus, :stack => [2, 1], :args => [:literal], :control_flow => :send
126
+ opcode 84, :meta_send_op_equal, :stack => [2, 1], :args => [:literal], :control_flow => :send
127
+ opcode 85, :meta_send_op_lt, :stack => [2, 1], :args => [:literal], :control_flow => :next
128
+ opcode 86, :meta_send_op_gt, :stack => [2, 1], :args => [:literal], :control_flow => :next
129
+ opcode 87, :meta_send_op_tequal, :stack => [2, 1], :args => [:literal], :control_flow => :send
130
+ opcode 88, :meta_send_call, :stack => [[1,2], 1], :args => [:literal, :count], :control_flow => :send
131
+
132
+ # More misc
133
+ opcode 89, :push_my_offset, :stack => [0, 1], :args => [:index], :control_flow => :next
134
+ opcode 90, :zsuper, :stack => [1, 1], :args => [:literal], :control_flow => :next
135
+ opcode 91, :push_block_arg, :stack => [0, 1], :args => [], :control_flow => :next
136
+ opcode 92, :push_undef, :stack => [0, 1], :args => [], :control_flow => :next
137
+ opcode 93, :push_stack_local, :stack => [0, 1], :args => [:which], :control_flow => :next
138
+ opcode 94, :set_stack_local, :stack => [1, 1], :args => [:which], :control_flow => :next
139
+ opcode 95, :push_has_block, :stack => [0, 1], :args => [], :control_flow => :next
140
+ opcode 96, :push_proc, :stack => [0, 1], :args => [], :control_flow => :next
141
+ opcode 97, :check_frozen, :stack => [1, 1], :args => [], :control_flow => :next
142
+ opcode 98, :cast_multi_value, :stack => [1, 1], :args => [], :control_flow => :next
143
+ opcode 99, :invoke_primitive, :stack => [[0,2], 1], :args => [:literal, :count], :control_flow => :next
144
+ opcode 100, :push_rubinius, :stack => [0, 1], :args => [], :control_flow => :next
145
+ opcode 101, :call_custom, :stack => [[1,2], 1], :args => [:literal, :count], :control_flow => :send
146
+ opcode 102, :meta_to_s, :stack => [1, 1], :args => [:literal], :control_flow => :send
147
+ opcode 103, :push_type, :stack => [0, 1], :args => [], :control_flow => :next
148
+ opcode 104, :push_mirror, :stack => [0, 1], :args => [], :control_flow => :next
149
+ end
150
+ end
@@ -0,0 +1,115 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ class Compiler
5
+ class Printer < Stage
6
+ def initialize
7
+ end
8
+ end
9
+
10
+ class ASTPrinter < Printer
11
+ def run
12
+ @input.ascii_graph
13
+ @output = @input
14
+ run_next
15
+ end
16
+ end
17
+
18
+ class SexpPrinter < Printer
19
+ def run
20
+ require 'pp'
21
+
22
+ puts @input.to_sexp.pretty_inspect
23
+ @output = @input
24
+ run_next
25
+ end
26
+ end
27
+
28
+ class MethodPrinter < Printer
29
+ attr_accessor :bytecode, :assembly
30
+
31
+ SEPARATOR_SIZE = 40
32
+
33
+ def method_names=(names)
34
+ return if names.empty?
35
+ @method_names = names.map { |n| n.to_sym }
36
+ end
37
+
38
+ def match?(name)
39
+ return true unless @method_names
40
+ @method_names.include? name
41
+ end
42
+
43
+ def print_header(code)
44
+ name = code.name.inspect
45
+ size = (SEPARATOR_SIZE - name.size - 2) / 2
46
+ size = 1 if size <= 0
47
+ puts "\n#{"=" * size} #{name} #{"=" * (size + name.size % 2)}"
48
+ print "Arguments: "
49
+ print "#{code.required_args} required, "
50
+ print "#{code.post_args} post, "
51
+ print "#{code.total_args} total"
52
+ print code.splat ? ", (splat #{code.splat})\n" : "\n"
53
+ puts "Arity: #{code.arity}"
54
+ print "Locals: #{code.local_count}"
55
+ print code.local_count > 0 ? ": #{code.local_names.join ", "}\n" : "\n"
56
+ puts "Stack size: #{code.stack_size}"
57
+ literals = code.literals.collect do |literal|
58
+ case literal
59
+ when CompiledCode
60
+ "<compiled code>"
61
+ else
62
+ literal.inspect
63
+ end
64
+ end
65
+ print "Literals: #{literals.size}"
66
+ print code.literals.size > 0 ? ": #{literals.join ", "}\n" : "\n"
67
+ print_lines code
68
+ puts
69
+ end
70
+
71
+ def print_footer
72
+ puts "-" * SEPARATOR_SIZE
73
+ end
74
+
75
+ def print_lines(code)
76
+ lines = code.lines
77
+ size = lines.size - 1
78
+ i = 1
79
+
80
+ if lines[0] == -1
81
+ puts "Line: #{lines[1]}"
82
+ i += 2
83
+ end
84
+
85
+ print "Lines to IP: "
86
+ while i < size
87
+ print "#{lines[i]}: #{lines[i - 1]}..#{lines[i + 1] - 1}"
88
+ i += 2
89
+ print ", " if i < size
90
+ end
91
+ puts
92
+ end
93
+
94
+ def print_method(code)
95
+ if match? code.name
96
+ print_header code
97
+ puts code.decode if @bytecode
98
+ print_footer
99
+ end
100
+
101
+ code.literals.each do |m|
102
+ next unless m.kind_of? Rubinius::CompiledCode
103
+ print_method m
104
+ end
105
+ end
106
+
107
+ def run
108
+ print_method @input
109
+
110
+ @output = @input
111
+ run_next
112
+ end
113
+ end
114
+ end
115
+ end