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,334 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ ##
4
+ # Used for the Rubinius::asm Compiler hook.
5
+
6
+ module Rubinius::ToolSet.current::TS
7
+ module AST
8
+ class Node
9
+ end
10
+
11
+ class ClosedScope < Node
12
+ end
13
+
14
+ class VariableAccess < Node
15
+ end
16
+
17
+ class VariableAssignment < Node
18
+ end
19
+
20
+ class Evaluator
21
+ attr_accessor :self
22
+
23
+ def initialize(generator, names, arguments)
24
+ @self = generator
25
+ @locals = {}
26
+
27
+ names.each_with_index do |name, index|
28
+ set_local name, arguments[index]
29
+ end
30
+ end
31
+
32
+ def execute(node)
33
+ node.execute self
34
+ end
35
+
36
+ def get_local(name)
37
+ @locals[name]
38
+ end
39
+
40
+ def set_local(name, value)
41
+ @locals[name] = value
42
+ end
43
+ end
44
+
45
+ class Container < ClosedScope
46
+ def execute(e)
47
+ @body.execute(e)
48
+ return true
49
+ end
50
+ end
51
+
52
+ class TrueLiteral < Node
53
+ def execute(e)
54
+ true
55
+ end
56
+ end
57
+
58
+ class FalseLiteral < Node
59
+ def execute(e)
60
+ false
61
+ end
62
+ end
63
+
64
+ class NilLiteral < Node
65
+ def execute(e)
66
+ nil
67
+ end
68
+ end
69
+
70
+ class Self < Node
71
+ def execute(e)
72
+ e.self
73
+ end
74
+ end
75
+
76
+ class And < Node
77
+ def execute(e)
78
+ @left.execute(e) and @right.execute(e)
79
+ end
80
+ end
81
+
82
+ class Or < And
83
+ def execute(e)
84
+ @left.execute(e) or @right.execute(e)
85
+ end
86
+ end
87
+
88
+ class Not < Node
89
+ def execute(e)
90
+ not @child.execute(e)
91
+ end
92
+ end
93
+
94
+ class Negate < Node
95
+ def execute(e)
96
+ -@child.execute(e)
97
+ end
98
+ end
99
+
100
+ class NumberLiteral < Node
101
+ def execute(e)
102
+ @value
103
+ end
104
+ end
105
+
106
+ class Literal < Node
107
+ def execute(e)
108
+ @value
109
+ end
110
+ end
111
+
112
+ class RegexLiteral < Node
113
+ def execute(e)
114
+ ::Regexp.new(@source, @options)
115
+ end
116
+ end
117
+
118
+ class StringLiteral < Node
119
+ def execute(e)
120
+ @string.dup
121
+ end
122
+ end
123
+
124
+ class DynamicString < StringLiteral
125
+ def execute(e)
126
+ str = @string.dup
127
+ @body.each do |x|
128
+ str << x.execute(e)
129
+ end
130
+
131
+ str
132
+ end
133
+ end
134
+
135
+ class DynamicRegex < DynamicString
136
+ def execute(e)
137
+ ::Regexp.new super(e)
138
+ end
139
+ end
140
+
141
+ class DynamicOnceRegex < DynamicRegex
142
+ def execute(e)
143
+ @value ||= super(e)
144
+ end
145
+ end
146
+
147
+ class If < Node
148
+ def execute(e)
149
+ if @condition.execute(e)
150
+ @then.execute(e) if @then
151
+ else
152
+ @else.execute(e) if @else
153
+ end
154
+ end
155
+ end
156
+
157
+ class While < Node
158
+ def execute(e)
159
+ if @check_first
160
+ while @condition.execute(e)
161
+ @body.execute(e)
162
+ end
163
+ else
164
+ begin
165
+ @body.execute(e)
166
+ end while @condition.execute(e)
167
+ end
168
+ end
169
+ end
170
+
171
+ class Until < While
172
+ def execute(e)
173
+ if @check_first
174
+ until @condition.execute(e)
175
+ @body.execute(e)
176
+ end
177
+ else
178
+ begin
179
+ @body.execute(e)
180
+ end until @condition.execute(e)
181
+ end
182
+ end
183
+ end
184
+
185
+ class Block < Node
186
+ def execute(e)
187
+ val = nil
188
+ @array.each do |x|
189
+ val = x.execute(e)
190
+ end
191
+
192
+ return val
193
+ end
194
+ end
195
+
196
+ class LocalVariableAccess < VariableAccess
197
+ def execute(e)
198
+ e.get_local @name
199
+ end
200
+ end
201
+
202
+ class LocalVariableAssignment < VariableAssignment
203
+ def execute(e)
204
+ e.set_local @name, @value.execute(e)
205
+ end
206
+ end
207
+
208
+ class ArrayLiteral < Node
209
+ def execute(e)
210
+ @body.map { |x| x.execute(e) }
211
+ end
212
+ end
213
+
214
+ class EmptyArray < Node
215
+ def execute(e)
216
+ []
217
+ end
218
+ end
219
+
220
+ class HashLiteral < Node
221
+ def execute(e)
222
+ args = @array.map { |x| x.execute(e) }
223
+ Hash[*args]
224
+ end
225
+ end
226
+
227
+ class SymbolLiteral < Node
228
+ def execute(e)
229
+ @value
230
+ end
231
+ end
232
+
233
+ class InstanceVariableAccess < VariableAccess
234
+ def execute(e)
235
+ e.self.instance_variable_get @name
236
+ end
237
+ end
238
+
239
+ class InstanceVariableAssignment < VariableAssignment
240
+ def execute(e)
241
+ e.self.instance_variable_set @name, @value.execute(e)
242
+ end
243
+ end
244
+
245
+ class GlobalVariableAccess < VariableAccess
246
+ def execute(e)
247
+ ::Rubinius::Globals[@name]
248
+ end
249
+ end
250
+
251
+ class GlobalVariableAssignment < VariableAssignment
252
+ def execute(e)
253
+ ::Rubinius::Globals[@name] = @value.execute(e)
254
+ end
255
+ end
256
+
257
+ class ConstantAccess < Node
258
+ def execute(e)
259
+ Object.const_get @name
260
+ end
261
+ end
262
+
263
+ class ScopedConstant < Node
264
+ def execute(e)
265
+ parent = @parent.execute(e)
266
+ parent.const_get @name
267
+ end
268
+ end
269
+
270
+ class ToplevelConstant < Node
271
+ def execute(e)
272
+ Object.const_get @name
273
+ end
274
+ end
275
+
276
+ class Send < Node
277
+ def execute_receiver(e)
278
+ if @receiver.kind_of? Self
279
+ e.self
280
+ else
281
+ @receiver.execute(e)
282
+ end
283
+ end
284
+
285
+ def execute(e)
286
+ receiver = execute_receiver(e)
287
+
288
+ receiver.__send__ @name
289
+ end
290
+ end
291
+
292
+ class SendWithArguments < Send
293
+ def execute(e)
294
+ arguments = @arguments.execute(e)
295
+ receiver = execute_receiver(e)
296
+
297
+ receiver.__send__ @name, *arguments
298
+ end
299
+ end
300
+
301
+ class ActualArguments < Node
302
+ def execute(e)
303
+ array = @array.map { |x| x.execute(e) }
304
+ array << @splat.execute if @splat.kind_of? SplatValue
305
+ array
306
+ end
307
+ end
308
+
309
+ class Yield < SendWithArguments
310
+ def execute(e)
311
+ # TODO
312
+ e.block.call(*@arguments.execute(e))
313
+ end
314
+ end
315
+
316
+ class ExecuteString < StringLiteral
317
+ def execute(e)
318
+ `#{@string.execute(e)}`
319
+ end
320
+ end
321
+
322
+ class ToString < Node
323
+ def execute(e)
324
+ @child.execute(e).to_s
325
+ end
326
+ end
327
+
328
+ class DynamicExecuteString < DynamicString
329
+ def execute(e)
330
+ `#{super(e)}`
331
+ end
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,646 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ class Generator
5
+ include GeneratorMethods
6
+
7
+ ##
8
+ # Jump label for the branch instructions. The use scenarios for labels:
9
+ # 1. Used and then set
10
+ # g.gif label
11
+ # ...
12
+ # label.set!
13
+ # 2. Set and then used
14
+ # label.set!
15
+ # ...
16
+ # g.git label
17
+ # 3. 1, 2
18
+ #
19
+ # Many labels are only used once. This class employs two small
20
+ # optimizations. First, for the case where a label is used once then set,
21
+ # the label merely records the point it was used and updates that location
22
+ # to the concrete IP when the label is set. In the case where the label is
23
+ # used multiple times, it records each location and updates them to an IP
24
+ # when the label is set. In both cases, once the label is set, each use
25
+ # after that updates the instruction stream with a concrete IP at the
26
+ # point the label is used. This avoids the need to ever record all the
27
+ # labels or search through the stream later to change symbolic labels into
28
+ # concrete IP's.
29
+
30
+ class Label
31
+ attr_accessor :position
32
+ attr_reader :used, :basic_block
33
+ alias_method :used?, :used
34
+
35
+ def initialize(generator)
36
+ @generator = generator
37
+ @basic_block = generator.new_basic_block
38
+ @position = nil
39
+ @used = false
40
+ @location = nil
41
+ @locations = nil
42
+ end
43
+
44
+ def set!
45
+ @position = @generator.ip
46
+ if @locations
47
+ @locations.each { |x| @generator.stream[x] = @position }
48
+ elsif @location
49
+ @generator.stream[@location] = @position
50
+ end
51
+
52
+ @generator.current_block.left = @basic_block
53
+ @generator.current_block.close
54
+ @generator.current_block = @basic_block
55
+ @basic_block.open
56
+ end
57
+
58
+ def used_at(ip)
59
+ if @position
60
+ @generator.stream[ip] = @position
61
+ elsif !@location
62
+ @location = ip
63
+ elsif @locations
64
+ @locations << ip
65
+ else
66
+ @locations = [@location, ip]
67
+ end
68
+ @used = true
69
+ end
70
+ end
71
+
72
+ class BasicBlock
73
+ attr_accessor :left
74
+ attr_accessor :right
75
+
76
+ def initialize(generator)
77
+ @generator = generator
78
+ @ip = generator.ip
79
+ @enter_size = nil
80
+ @max_size = 0
81
+ @min_size = 0
82
+ @exit_ip = 0
83
+ @exit_size = nil
84
+ @stack = 0
85
+ @left = nil
86
+ @right = nil
87
+ @visited = false
88
+ @closed = false
89
+ end
90
+
91
+ def add_stack(read, write)
92
+ read_change = @stack - read
93
+ @min_size = read_change if read_change < @min_size
94
+
95
+ @stack += (write - read)
96
+
97
+ @max_size = @stack if @stack > @max_size
98
+ end
99
+
100
+ def open
101
+ @ip = @generator.ip
102
+ end
103
+
104
+ def close(record_exit=false)
105
+ @closed = true
106
+
107
+ if record_exit
108
+ @exit_size = @stack
109
+ @exit_ip = @generator.ip - 1
110
+ end
111
+ end
112
+
113
+ def location(ip=nil)
114
+ ip ||= @ip
115
+ line = @generator.ip_to_line(ip)
116
+ "#{@generator.name}: line: #{line}, IP: #{ip}"
117
+ end
118
+
119
+ SEPARATOR_SIZE = 40
120
+
121
+ def invalid(message)
122
+ if $DEBUG
123
+ puts message
124
+ name = @generator.name.inspect
125
+ size = (SEPARATOR_SIZE - name.size - 2) / 2
126
+ size = 1 if size <= 0
127
+ puts "\n#{"=" * size} #{name} #{"=" * (size + name.size % 2)}"
128
+
129
+ literals = @generator.literals
130
+ names = @generator.local_names
131
+ stream = @generator.stream
132
+ i = 0
133
+ n = stream.size
134
+ stack = 0
135
+
136
+ while i < n
137
+ insn = Rubinius::InstructionSet[stream[i]]
138
+ printf "[%3d] %04d %-28s" % [stack, i, insn.opcode.inspect]
139
+
140
+ args = stream[i+1, insn.size-1]
141
+ if insn.size > 1
142
+ insn.args.each_with_index do |kind, index|
143
+ arg = args[index]
144
+ case kind
145
+ when :literal
146
+ printf "%s " % literals[arg].inspect
147
+ when :local
148
+ printf "%s " % (names ? names[arg] : arg)
149
+ else
150
+ printf "%d " % arg
151
+ end
152
+ end
153
+ end
154
+
155
+ puts
156
+
157
+ if insn.variable_stack?
158
+ use = insn.stack_consumed
159
+ if use.kind_of? Array
160
+ use = args[use[1] - 1] + use[0]
161
+ end
162
+
163
+ pro = insn.stack_produced
164
+ if pro.kind_of? Array
165
+ pro = (args[pro[1] - 1] * pro[2]) + pro[0]
166
+ end
167
+
168
+ stack += pro - use
169
+ else
170
+ stack += insn.stack_difference
171
+ end
172
+
173
+ i += insn.size
174
+ end
175
+
176
+ puts "-" * SEPARATOR_SIZE
177
+ end
178
+
179
+ raise CompileError, message
180
+ end
181
+
182
+ def visited?
183
+ @visited
184
+ end
185
+
186
+ def validate_stack
187
+ @enter_size = 0
188
+
189
+ stack = [self]
190
+ until stack.empty?
191
+ bb = stack.shift
192
+ bb.flow_stack_size stack
193
+ end
194
+ end
195
+
196
+ def flow_stack_size(stack)
197
+ unless @visited
198
+ @visited = true
199
+
200
+ @generator.accumulate_stack(@enter_size + @max_size)
201
+
202
+ net_size = @enter_size + @stack
203
+
204
+ if net_size < 0
205
+ invalid "net stack underflow in block starting at #{location}"
206
+ end
207
+
208
+ if @enter_size + @min_size < 0
209
+ invalid "minimum stack underflow in block starting at #{location}"
210
+ end
211
+
212
+ if @exit_size and @enter_size + @exit_size < 1
213
+ invalid "exit stack underflow in block starting at #{location(@exit_ip)}"
214
+ end
215
+
216
+ if @left
217
+ @left.check_stack net_size
218
+ stack.push @left unless @left.visited?
219
+ end
220
+
221
+ if @right
222
+ @right.check_stack net_size
223
+ stack.push @right unless @right.visited?
224
+ end
225
+ end
226
+ end
227
+
228
+ def check_stack(stack_size)
229
+ if @enter_size
230
+ unless stack_size == @enter_size
231
+ invalid "unbalanced stack at #{location}: #{stack_size} != #{@enter_size}"
232
+ end
233
+ else
234
+ if not @closed
235
+ invalid "control fails to exit properly at #{location}"
236
+ end
237
+
238
+ @enter_size = stack_size
239
+ end
240
+ end
241
+ end
242
+
243
+ def initialize
244
+ @stream = []
245
+ @literals_map = Hash.new { |h,k| h[k] = add_literal(k) }
246
+ @literals = []
247
+ @ip = 0
248
+ @modstack = []
249
+ @break = nil
250
+ @redo = nil
251
+ @next = nil
252
+ @retry = nil
253
+ @last_line = nil
254
+ @file = nil
255
+ @lines = []
256
+ @primitive = nil
257
+ @instruction = nil
258
+ @for_block = nil
259
+ @for_module_body = nil
260
+
261
+ @required_args = 0
262
+ @post_args = 0
263
+ @total_args = 0
264
+
265
+ @detected_args = 0
266
+ @detected_locals = 0
267
+
268
+ @splat_index = nil
269
+ @local_names = nil
270
+ @block_index = nil
271
+ @local_count = 0
272
+
273
+ @state = []
274
+ @generators = []
275
+
276
+ @stack_locals = 0
277
+
278
+ @enter_block = new_basic_block
279
+ @current_block = @enter_block
280
+ @max_stack = 0
281
+ end
282
+
283
+ attr_reader :ip, :stream, :iseq, :literals
284
+ attr_accessor :break, :redo, :next, :retry, :file, :name,
285
+ :required_args, :post_args, :total_args, :splat_index,
286
+ :local_count, :local_names, :primitive, :for_block, :for_module_body,
287
+ :current_block, :detected_args, :detected_locals,
288
+ :block_index
289
+
290
+ def execute(node)
291
+ node.bytecode self
292
+ end
293
+
294
+ alias_method :run, :execute
295
+
296
+ # Formalizers
297
+
298
+ def encode
299
+ @iseq = Rubinius::InstructionSequence.new @stream.to_tuple
300
+
301
+ begin
302
+ # Validate the stack and calculate the max depth
303
+ @enter_block.validate_stack
304
+ rescue Exception => e
305
+ if $DEBUG
306
+ puts "Error computing stack for #{@name}: #{e.message} (#{e.class})"
307
+ end
308
+ raise e
309
+ end
310
+
311
+ @generators.each { |x| @literals[x].encode }
312
+ end
313
+
314
+ def package(klass)
315
+ @generators.each { |x| @literals[x] = @literals[x].package klass }
316
+
317
+ code = klass.new
318
+ code.iseq = @iseq
319
+ code.literals = @literals.to_tuple
320
+ code.lines = @lines.to_tuple
321
+
322
+ code.required_args = @required_args
323
+ code.post_args = @post_args
324
+ code.total_args = @total_args
325
+ code.splat = @splat_index
326
+ code.block_index = @block_index
327
+ code.local_count = @local_count
328
+ code.local_names = @local_names.to_tuple if @local_names
329
+
330
+ code.stack_size = max_stack_size
331
+ code.file = @file
332
+ code.name = @name
333
+ code.primitive = @primitive
334
+
335
+ if @for_block
336
+ code.add_metadata :for_block, true
337
+ end
338
+
339
+ if @for_module_body
340
+ code.add_metadata :for_module_body, true
341
+ end
342
+
343
+ code
344
+ end
345
+
346
+ def use_detected
347
+ if @required_args < @detected_args
348
+ @required_args = @detected_args
349
+ end
350
+
351
+ if @total_args < @detected_args
352
+ @total_args = @detected_args
353
+ end
354
+
355
+ if @local_count < @detected_locals
356
+ @local_count = @detected_locals
357
+ end
358
+ end
359
+
360
+ # Commands (these don't generate data in the stream)
361
+
362
+ def state
363
+ @state.last
364
+ end
365
+
366
+ def push_state(scope)
367
+ @state << AST::State.new(scope)
368
+ end
369
+
370
+ def pop_state
371
+ @state.pop
372
+ end
373
+
374
+ def push_modifiers
375
+ @modstack << [@break, @redo, @next, @retry]
376
+ end
377
+
378
+ def pop_modifiers
379
+ @break, @redo, @next, @retry = @modstack.pop
380
+ end
381
+
382
+ def definition_line(line)
383
+ unless @stream.empty?
384
+ raise Exception, "only use #definition_line first"
385
+ end
386
+
387
+ @lines << -1
388
+ @lines << line
389
+
390
+ @last_line = line
391
+ end
392
+
393
+ def set_line(line)
394
+ raise Exception, "source code line cannot be nil" unless line
395
+
396
+ if !@last_line
397
+ @lines << @ip
398
+ @lines << line
399
+ @last_line = line
400
+ elsif line != @last_line
401
+ if @lines[-2] == @ip
402
+ @lines[-1] = line
403
+ else
404
+ @lines << @ip
405
+ @lines << line
406
+ end
407
+
408
+ @last_line = line
409
+ end
410
+ end
411
+
412
+ def line
413
+ @last_line
414
+ end
415
+
416
+ def ip_to_line(ip)
417
+ total = @lines.size - 2
418
+ i = 0
419
+
420
+ while i < total
421
+ if ip >= @lines[i] and ip <= @lines[i+2]
422
+ return @lines[i+1]
423
+ end
424
+
425
+ i += 2
426
+ end
427
+ end
428
+
429
+ def close
430
+ if @lines.empty?
431
+ msg = "closing a method definition with no line info: #{file}:#{line}"
432
+ raise Exception, msg
433
+ end
434
+
435
+ @lines << @ip
436
+ end
437
+
438
+ def send_primitive(name)
439
+ @primitive = name
440
+ end
441
+
442
+ def new_label
443
+ Label.new(self)
444
+ end
445
+
446
+ # Aliases
447
+
448
+ alias_method :dup, :dup_top
449
+ alias_method :git, :goto_if_true
450
+ alias_method :gif, :goto_if_false
451
+ alias_method :swap, :swap_stack
452
+
453
+ # Helpers
454
+
455
+ def new_basic_block
456
+ BasicBlock.new self
457
+ end
458
+
459
+ def accumulate_stack(size)
460
+ @max_stack = size if size > @max_stack
461
+ end
462
+
463
+ def max_stack_size
464
+ size = @max_stack + @local_count + @stack_locals
465
+ size += 1 if @for_block
466
+ size
467
+ end
468
+
469
+ def new_stack_local
470
+ idx = @stack_locals
471
+ @stack_locals += 1
472
+ return idx
473
+ end
474
+
475
+ def push(what)
476
+ case what
477
+ when :true
478
+ push_true
479
+ when :false
480
+ push_false
481
+ when :self
482
+ push_self
483
+ when :nil
484
+ push_nil
485
+ when Integer
486
+ push_int what
487
+ else
488
+ raise CompileError, "Unknown push argument '#{what.inspect}'"
489
+ end
490
+ end
491
+
492
+ def push_generator(generator)
493
+ index = push_literal generator
494
+ @generators << index
495
+ index
496
+ end
497
+
498
+ # Find the index for the specified literal, or create a new slot if the
499
+ # literal has not been encountered previously.
500
+ def find_literal(literal)
501
+ @literals_map[literal]
502
+ end
503
+
504
+ # Add literal exists to allow RegexLiteral's to create a new regex literal
505
+ # object at run-time. All other literals should be added via find_literal,
506
+ # which re-use an existing matching literal if one exists.
507
+ def add_literal(literal)
508
+ index = @literals.size
509
+ @literals << literal
510
+ return index
511
+ end
512
+
513
+ # Pushes the specified literal value into the literal's tuple
514
+ def push_literal(literal)
515
+ index = find_literal literal
516
+ emit_push_literal index
517
+ return index
518
+ end
519
+
520
+ # Puts +what+ is the literals tuple without trying to see if
521
+ # something that is like +what+ is already there.
522
+ def push_unique_literal(literal)
523
+ index = add_literal literal
524
+ emit_push_literal index
525
+ return index
526
+ end
527
+
528
+ # Pushes the literal value on the stack into the specified position in the
529
+ # literals tuple. Most timees, push_literal should be used instead; this
530
+ # method exists to support RegexLiteral, where the compiled literal value
531
+ # (a Regex object) does not exist until runtime.
532
+ def push_literal_at(index)
533
+ emit_push_literal index
534
+ return index
535
+ end
536
+
537
+ # The push_const instruction itself is unused right now. The instruction
538
+ # parser does not emit a GeneratorMethods#push_const. This method/opcode
539
+ # was used in the compiler before the push_const_fast instruction. Rather
540
+ # than changing the compiler code, this helper was used.
541
+ def push_const(name)
542
+ push_const_fast find_literal(name)
543
+ end
544
+
545
+ # The find_const instruction itself is unused right now. The instruction
546
+ # parser does not emit a GeneratorMethods#find_const. This method/opcode
547
+ # was used in the compiler before the find_const_fast instruction. Rather
548
+ # than changing the compiler code, this helper was used.
549
+ def find_const(name)
550
+ find_const_fast find_literal(name)
551
+ end
552
+
553
+ def push_local(idx)
554
+ if @detected_locals <= idx
555
+ @detected_locals = idx + 1
556
+ end
557
+
558
+ super
559
+ end
560
+
561
+ def set_local(idx)
562
+ if @detected_locals <= idx
563
+ @detected_locals = idx + 1
564
+ end
565
+
566
+ super
567
+ end
568
+
569
+ # Minor meta operations that can be used to detect
570
+ # the number of method arguments needed
571
+ def push_arg(idx)
572
+ push_local(idx)
573
+ @detected_args = @detected_locals
574
+ end
575
+
576
+ def set_arg(idx)
577
+ set_local(idx)
578
+ @detected_args = @detected_locals
579
+ end
580
+
581
+ def last_match(mode, which)
582
+ push_int Integer(mode)
583
+ push_int Integer(which)
584
+ invoke_primitive :regexp_last_match_result, 2
585
+ end
586
+
587
+ def send(meth, count, priv=false)
588
+ allow_private if priv
589
+
590
+ unless count.kind_of? Fixnum
591
+ raise CompileError, "count must be a number"
592
+ end
593
+
594
+ idx = find_literal(meth)
595
+
596
+ # Don't use send_method, it's only for when the syntax
597
+ # specified no arguments and no parens.
598
+ send_stack idx, count
599
+ end
600
+
601
+ # Do a private send to self with no arguments specified, ie, a vcall
602
+ # style send.
603
+ def send_vcall(meth)
604
+ idx = find_literal(meth)
605
+ send_method idx
606
+ end
607
+
608
+ def send_with_block(meth, count, priv=false)
609
+ allow_private if priv
610
+
611
+ unless count.kind_of? Fixnum
612
+ raise CompileError, "count must be a number"
613
+ end
614
+
615
+ idx = find_literal(meth)
616
+
617
+ send_stack_with_block idx, count
618
+ end
619
+
620
+ def send_with_splat(meth, args, priv=false, concat=false)
621
+ val = 0
622
+ val |= Rubinius::InstructionSet::CALL_FLAG_CONCAT if concat
623
+ set_call_flags val unless val == 0
624
+
625
+ allow_private if priv
626
+
627
+ idx = find_literal(meth)
628
+ send_stack_with_splat idx, args
629
+ end
630
+
631
+ def send_super(meth, args, splat=false)
632
+ idx = find_literal(meth)
633
+
634
+ if splat
635
+ send_super_stack_with_splat idx, args
636
+ else
637
+ send_super_stack_with_block idx, args
638
+ end
639
+ end
640
+
641
+ def meta_to_s(name=:to_s, priv=true)
642
+ allow_private if priv
643
+ super find_literal(name)
644
+ end
645
+ end
646
+ end