Class: CodeTools::Generator

Inherits:
Object
  • Object
show all
Includes:
GeneratorMethods
Defined in:
lib/rubinius/compiler/generator.rb

Defined Under Namespace

Classes: BasicBlock, Label

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from GeneratorMethods

#add_scope, #allow_private, #call_custom, #cast_array, #cast_for_multi_block_arg, #cast_for_single_block_arg, #cast_for_splat_block_arg, #cast_multi_value, #check_frozen, #check_interrupts, #check_serial, #check_serial_private, #clear_exception, #create_block, #dup_many, #dup_top, #emit_push_literal, #ensure_return, #find_const_fast, #goto, #goto_if_equal, #goto_if_false, #goto_if_nil, #goto_if_not_equal, #goto_if_not_nil, #goto_if_not_undefined, #goto_if_true, #goto_if_undefined, #instance_of, #invoke_primitive, #is_nil, #kind_of, #make_array, #meta_push_0, #meta_push_1, #meta_push_2, #meta_push_neg_1, #meta_send_call, #meta_send_op_equal, #meta_send_op_gt, #meta_send_op_lt, #meta_send_op_minus, #meta_send_op_plus, #meta_send_op_tequal, #move_down, #noop, #passed_arg, #passed_blockarg, #pop, #pop_many, #pop_unwind, #push_block, #push_block_arg, #push_const_fast, #push_cpath_top, #push_current_exception, #push_exception_state, #push_false, #push_has_block, #push_int, #push_ivar, #push_local_depth, #push_mirror, #push_my_field, #push_my_offset, #push_nil, #push_proc, #push_rubinius, #push_scope, #push_self, #push_stack_local, #push_true, #push_type, #push_undef, #push_variables, #raise_break, #raise_exc, #raise_return, #reraise, #restore_exception_state, #ret, #rotate, #send_method, #send_stack, #send_stack_with_block, #send_stack_with_splat, #send_super_stack_with_block, #send_super_stack_with_splat, #set_call_flags, #set_const, #set_const_at, #set_ivar, #set_literal, #set_local_depth, #set_stack_local, #setup_unwind, #shift_array, #store_my_field, #string_append, #string_build, #string_dup, #swap_stack, #yield_debugger, #yield_splat, #yield_stack, #zsuper

Constructor Details

#initializeGenerator

Returns a new instance of Generator.



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/rubinius/compiler/generator.rb', line 243

def initialize
  @stream = []
  @literals_map = Hash.new { |h,k| h[k] = add_literal(k) }
  @literals = []
  @ip = 0
  @modstack = []
  @break = nil
  @redo = nil
  @next = nil
  @retry = nil
  @last_line = nil
  @file = nil
  @lines = []
  @primitive = nil
  @instruction = nil
  @for_block = nil
  @for_module_body = nil

  @required_args = 0
  @post_args = 0
  @total_args = 0
  @arity = 0

  @detected_args = 0
  @detected_locals = 0

  @splat_index = nil
  @local_names = nil
  @block_index = nil
  @keywords = nil
  @local_count = 0

  @state = []
  @generators = []

  @stack_locals = 0

  @enter_block = new_basic_block
  @current_block = @enter_block
  @max_stack = 0
end

Instance Attribute Details

#arityObject

Returns the value of attribute arity.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def arity
  @arity
end

#block_indexObject

Returns the value of attribute block_index.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def block_index
  @block_index
end

#breakObject

Returns the value of attribute break.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def break
  @break
end

#current_blockObject

Returns the value of attribute current_block.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def current_block
  @current_block
end

#detected_argsObject

Returns the value of attribute detected_args.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def detected_args
  @detected_args
end

#detected_localsObject

Returns the value of attribute detected_locals.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def detected_locals
  @detected_locals
end

#fileObject

Returns the value of attribute file.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def file
  @file
end

#for_blockObject

Returns the value of attribute for_block.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def for_block
  @for_block
end

#for_module_bodyObject

Returns the value of attribute for_module_body.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def for_module_body
  @for_module_body
end

#ipObject (readonly)

Returns the value of attribute ip.



285
286
287
# File 'lib/rubinius/compiler/generator.rb', line 285

def ip
  @ip
end

#iseqObject (readonly)

Returns the value of attribute iseq.



285
286
287
# File 'lib/rubinius/compiler/generator.rb', line 285

def iseq
  @iseq
end

#keywordsObject

Returns the value of attribute keywords.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def keywords
  @keywords
end

#literalsObject (readonly)

Returns the value of attribute literals.



285
286
287
# File 'lib/rubinius/compiler/generator.rb', line 285

def literals
  @literals
end

#local_countObject

Returns the value of attribute local_count.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def local_count
  @local_count
end

#local_namesObject

Returns the value of attribute local_names.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def local_names
  @local_names
end

#nameObject

Returns the value of attribute name.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def name
  @name
end

#nextObject

Returns the value of attribute next.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def next
  @next
end

#post_argsObject

Returns the value of attribute post_args.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def post_args
  @post_args
end

#primitiveObject

Returns the value of attribute primitive.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def primitive
  @primitive
end

#redoObject

Returns the value of attribute redo.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def redo
  @redo
end

#required_argsObject

Returns the value of attribute required_args.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def required_args
  @required_args
end

#retryObject

Returns the value of attribute retry.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def retry
  @retry
end

#splat_indexObject

Returns the value of attribute splat_index.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def splat_index
  @splat_index
end

#streamObject (readonly)

Returns the value of attribute stream.



285
286
287
# File 'lib/rubinius/compiler/generator.rb', line 285

def stream
  @stream
end

#total_argsObject

Returns the value of attribute total_args.



286
287
288
# File 'lib/rubinius/compiler/generator.rb', line 286

def total_args
  @total_args
end

Instance Method Details

#accumulate_stack(size) ⇒ Object



469
470
471
# File 'lib/rubinius/compiler/generator.rb', line 469

def accumulate_stack(size)
  @max_stack = size if size > @max_stack
end

#add_literal(literal) ⇒ Object

Add literal exists to allow RegexLiteral’s to create a new regex literal object at run-time. All other literals should be added via find_literal, which re-use an existing matching literal if one exists.



517
518
519
520
521
# File 'lib/rubinius/compiler/generator.rb', line 517

def add_literal(literal)
  index = @literals.size
  @literals << literal
  return index
end

#closeObject



433
434
435
436
437
438
439
440
# File 'lib/rubinius/compiler/generator.rb', line 433

def close
  if @lines.empty?
    msg = "closing a method definition with no line info: #{file}:#{line}"
    raise Exception, msg
  end

  @lines << @ip
end

#definition_line(line) ⇒ Object



386
387
388
389
390
391
392
393
394
395
# File 'lib/rubinius/compiler/generator.rb', line 386

def definition_line(line)
  unless @stream.empty?
    raise Exception, "only use #definition_line first"
  end

  @lines << -1
  @lines << line

  @last_line = line
end

#encodeObject

Formalizers



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/rubinius/compiler/generator.rb', line 300

def encode
  @iseq = Rubinius::InstructionSequence.new @stream.to_tuple

  begin
    # Validate the stack and calculate the max depth
    @enter_block.validate_stack
  rescue Exception => e
    if $DEBUG
      puts "Error computing stack for #{@name}: #{e.message} (#{e.class})"
    end
    raise e
  end

  @generators.each { |x| @literals[x].encode }
end

#execute(node) ⇒ Object Also known as: run



292
293
294
# File 'lib/rubinius/compiler/generator.rb', line 292

def execute(node)
  node.bytecode self
end

#find_const(name) ⇒ Object

The find_const instruction itself is unused right now. The instruction parser does not emit a GeneratorMethods#find_const. This method/opcode was used in the compiler before the find_const_fast instruction. Rather than changing the compiler code, this helper was used.



559
560
561
# File 'lib/rubinius/compiler/generator.rb', line 559

def find_const(name)
  find_const_fast find_literal(name)
end

#find_literal(literal) ⇒ Object

Find the index for the specified literal, or create a new slot if the literal has not been encountered previously.



510
511
512
# File 'lib/rubinius/compiler/generator.rb', line 510

def find_literal(literal)
  @literals_map[literal]
end

#ip_to_line(ip) ⇒ Object



420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/rubinius/compiler/generator.rb', line 420

def ip_to_line(ip)
  total = @lines.size - 2
  i = 0

  while i < total
    if ip >= @lines[i] and ip <= @lines[i+2]
      return @lines[i+1]
    end

    i += 2
  end
end

#last_match(mode, which) ⇒ Object



591
592
593
594
595
# File 'lib/rubinius/compiler/generator.rb', line 591

def last_match(mode, which)
  push_int Integer(mode)
  push_int Integer(which)
  invoke_primitive :regexp_last_match_result, 2
end

#lineObject



416
417
418
# File 'lib/rubinius/compiler/generator.rb', line 416

def line
  @last_line
end

#max_stack_sizeObject



473
474
475
476
477
# File 'lib/rubinius/compiler/generator.rb', line 473

def max_stack_size
  size = @max_stack + @local_count + @stack_locals
  size += 1 if @for_block
  size
end

#meta_to_s(name = :to_s, priv = true) ⇒ Object



651
652
653
654
# File 'lib/rubinius/compiler/generator.rb', line 651

def meta_to_s(name=:to_s, priv=true)
  allow_private if priv
  super find_literal(name)
end

#new_basic_blockObject

Helpers



465
466
467
# File 'lib/rubinius/compiler/generator.rb', line 465

def new_basic_block
  BasicBlock.new self
end

#new_labelObject



446
447
448
# File 'lib/rubinius/compiler/generator.rb', line 446

def new_label
  Label.new(self)
end

#new_stack_localObject



479
480
481
482
483
# File 'lib/rubinius/compiler/generator.rb', line 479

def new_stack_local
  idx = @stack_locals
  @stack_locals += 1
  return idx
end

#package(klass) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/rubinius/compiler/generator.rb', line 316

def package(klass)
  @generators.each { |x| @literals[x] = @literals[x].package klass }

  code = klass.new
  code.iseq           = @iseq
  code.literals       = @literals.to_tuple
  code.lines          = @lines.to_tuple

  code.required_args  = @required_args
  code.post_args      = @post_args
  code.total_args     = @total_args
  code.splat          = @splat_index
  code.block_index    = @block_index
  code.arity          = @arity
  code.local_count    = @local_count
  code.local_names    = @local_names.to_tuple if @local_names
  code.keywords       = @keywords.to_tuple if @keywords

  code.stack_size     = max_stack_size
  code.file           = @file
  code.name           = @name
  code.primitive      = @primitive

  if @for_block
    code. :for_block, true
  end

  if @for_module_body
    code. :for_module_body, true
  end

  code
end

#pop_modifiersObject



382
383
384
# File 'lib/rubinius/compiler/generator.rb', line 382

def pop_modifiers
  @break, @redo, @next, @retry = @modstack.pop
end

#pop_stateObject



374
375
376
# File 'lib/rubinius/compiler/generator.rb', line 374

def pop_state
  @state.pop
end

#push(what) ⇒ Object



485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/rubinius/compiler/generator.rb', line 485

def push(what)
  case what
  when :true
    push_true
  when :false
    push_false
  when :self
    push_self
  when :nil
    push_nil
  when Integer
    push_int what
  else
    raise CompileError, "Unknown push argument '#{what.inspect}'"
  end
end

#push_arg(idx) ⇒ Object

Minor meta operations that can be used to detect the number of method arguments needed



581
582
583
584
# File 'lib/rubinius/compiler/generator.rb', line 581

def push_arg(idx)
  push_local(idx)
  @detected_args = @detected_locals
end

#push_const(name) ⇒ Object

The push_const instruction itself is unused right now. The instruction parser does not emit a GeneratorMethods#push_const. This method/opcode was used in the compiler before the push_const_fast instruction. Rather than changing the compiler code, this helper was used.



551
552
553
# File 'lib/rubinius/compiler/generator.rb', line 551

def push_const(name)
  push_const_fast find_literal(name)
end

#push_generator(generator) ⇒ Object



502
503
504
505
506
# File 'lib/rubinius/compiler/generator.rb', line 502

def push_generator(generator)
  index = push_literal generator
  @generators << index
  index
end

#push_literal(literal) ⇒ Object

Pushes the specified literal value into the literal’s tuple



524
525
526
527
528
# File 'lib/rubinius/compiler/generator.rb', line 524

def push_literal(literal)
  index = find_literal literal
  emit_push_literal index
  return index
end

#push_literal_at(index) ⇒ Object

Pushes the literal value on the stack into the specified position in the literals tuple. Most timees, push_literal should be used instead; this method exists to support RegexLiteral, where the compiled literal value (a Regex object) does not exist until runtime.



542
543
544
545
# File 'lib/rubinius/compiler/generator.rb', line 542

def push_literal_at(index)
  emit_push_literal index
  return index
end

#push_local(idx) ⇒ Object



563
564
565
566
567
568
569
# File 'lib/rubinius/compiler/generator.rb', line 563

def push_local(idx)
  if @detected_locals <= idx
    @detected_locals = idx + 1
  end

  super
end

#push_modifiersObject



378
379
380
# File 'lib/rubinius/compiler/generator.rb', line 378

def push_modifiers
  @modstack << [@break, @redo, @next, @retry]
end

#push_state(scope) ⇒ Object



370
371
372
# File 'lib/rubinius/compiler/generator.rb', line 370

def push_state(scope)
  @state << AST::State.new(scope)
end

#push_unique_literal(literal) ⇒ Object

Puts what is the literals tuple without trying to see if something that is like what is already there.



532
533
534
535
536
# File 'lib/rubinius/compiler/generator.rb', line 532

def push_unique_literal(literal)
  index = add_literal literal
  emit_push_literal index
  return index
end

#send(meth, count, priv = false) ⇒ Object



597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/rubinius/compiler/generator.rb', line 597

def send(meth, count, priv=false)
  allow_private if priv

  unless count.kind_of? Fixnum
    raise CompileError, "count must be a number"
  end

  idx = find_literal(meth)

  # Don't use send_method, it's only for when the syntax
  # specified no arguments and no parens.
  send_stack idx, count
end

#send_primitive(name) ⇒ Object



442
443
444
# File 'lib/rubinius/compiler/generator.rb', line 442

def send_primitive(name)
  @primitive = name
end

#send_super(meth, args, splat = false) ⇒ Object



641
642
643
644
645
646
647
648
649
# File 'lib/rubinius/compiler/generator.rb', line 641

def send_super(meth, args, splat=false)
  idx = find_literal(meth)

  if splat
    send_super_stack_with_splat idx, args
  else
    send_super_stack_with_block idx, args
  end
end

#send_vcall(meth) ⇒ Object

Do a private send to self with no arguments specified, ie, a vcall style send.



613
614
615
616
# File 'lib/rubinius/compiler/generator.rb', line 613

def send_vcall(meth)
  idx = find_literal(meth)
  send_method idx
end

#send_with_block(meth, count, priv = false) ⇒ Object



618
619
620
621
622
623
624
625
626
627
628
# File 'lib/rubinius/compiler/generator.rb', line 618

def send_with_block(meth, count, priv=false)
  allow_private if priv

  unless count.kind_of? Fixnum
    raise CompileError, "count must be a number"
  end

  idx = find_literal(meth)

  send_stack_with_block idx, count
end

#send_with_splat(meth, args, priv = false, concat = false) ⇒ Object



630
631
632
633
634
635
636
637
638
639
# File 'lib/rubinius/compiler/generator.rb', line 630

def send_with_splat(meth, args, priv=false, concat=false)
  val = 0
  val |= Rubinius::InstructionSet::CALL_FLAG_CONCAT if concat
  set_call_flags val unless val == 0

  allow_private if priv

  idx = find_literal(meth)
  send_stack_with_splat idx, args
end

#set_arg(idx) ⇒ Object



586
587
588
589
# File 'lib/rubinius/compiler/generator.rb', line 586

def set_arg(idx)
  set_local(idx)
  @detected_args = @detected_locals
end

#set_line(line) ⇒ Object

Raises:

  • (Exception)


397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/rubinius/compiler/generator.rb', line 397

def set_line(line)
  raise Exception, "source code line cannot be nil" unless line

  if !@last_line
    @lines << @ip
    @lines << line
    @last_line = line
  elsif line != @last_line
    if @lines[-2] == @ip
      @lines[-1] = line
    else
      @lines << @ip
      @lines << line
    end

    @last_line = line
  end
end

#set_local(idx) ⇒ Object



571
572
573
574
575
576
577
# File 'lib/rubinius/compiler/generator.rb', line 571

def set_local(idx)
  if @detected_locals <= idx
    @detected_locals = idx + 1
  end

  super
end

#stateObject

Commands (these don’t generate data in the stream)



366
367
368
# File 'lib/rubinius/compiler/generator.rb', line 366

def state
  @state.last
end

#use_detectedObject



350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/rubinius/compiler/generator.rb', line 350

def use_detected
  if @required_args < @detected_args
    @required_args = @detected_args
  end

  if @total_args < @detected_args
    @total_args = @detected_args
  end

  if @local_count < @detected_locals
    @local_count = @detected_locals
  end
end