rubinius-compiler 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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