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,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