@@ -12,8 +12,7 @@ class InstructionSequence
12
12
# and other transformations like instruction specialization.
13
13
class InstructionList
14
14
class Node
15
- attr_reader :instruction
16
- attr_accessor :next_node
15
+ attr_accessor :instruction , :next_node
17
16
18
17
def initialize ( instruction , next_node = nil )
19
18
@instruction = instruction
@@ -29,11 +28,16 @@ def initialize
29
28
end
30
29
31
30
def each
31
+ return to_enum ( __method__ ) unless block_given?
32
+ each_node { |node | yield node . instruction }
33
+ end
34
+
35
+ def each_node
32
36
return to_enum ( __method__ ) unless block_given?
33
37
node = head_node
34
38
35
39
while node
36
- yield node . instruction
40
+ yield node
37
41
node = node . next_node
38
42
end
39
43
end
@@ -210,7 +214,10 @@ def eval
210
214
def to_a
211
215
versions = RUBY_VERSION . split ( "." ) . map ( &:to_i )
212
216
213
- # First, set it up so that all of the labels get their correct name.
217
+ # First, specialize any instructions that need to be specialized.
218
+ specialize_instructions! if options . specialized_instruction?
219
+
220
+ # Next, set it up so that all of the labels get their correct name.
214
221
insns . each . inject ( 0 ) do |length , insn |
215
222
case insn
216
223
when Integer , Symbol
@@ -261,6 +268,92 @@ def to_a
261
268
]
262
269
end
263
270
271
+ def specialize_instructions!
272
+ insns . each_node do |node |
273
+ case node . instruction
274
+ when PutObject , PutString
275
+ next unless node . next_node
276
+ next if node . instruction . is_a? ( PutObject ) && !node . instruction . object . is_a? ( String )
277
+
278
+ next_node = node . next_node
279
+ next unless next_node . instruction . is_a? ( Send )
280
+ next if next_node . instruction . block_iseq
281
+
282
+ calldata = next_node . instruction . calldata
283
+ next unless calldata . flags == CallData ::CALL_ARGS_SIMPLE
284
+
285
+ case calldata . method
286
+ when :freeze
287
+ node . instruction = OptStrFreeze . new ( node . instruction . object , calldata )
288
+ node . next_node = next_node . next_node
289
+ when :-@
290
+ node . instruction = OptStrUMinus . new ( node . instruction . object , calldata )
291
+ node . next_node = next_node . next_node
292
+ end
293
+ when Send
294
+ calldata = node . instruction . calldata
295
+
296
+ if !node . instruction . block_iseq && !calldata . flag? ( CallData ::CALL_ARGS_BLOCKARG )
297
+ # Specialize the send instruction. If it doesn't have a block
298
+ # attached, then we will replace it with an opt_send_without_block
299
+ # and do further specializations based on the called method and
300
+ # the number of arguments.
301
+ node . instruction =
302
+ case [ calldata . method , calldata . argc ]
303
+ when [ :length , 0 ]
304
+ OptLength . new ( calldata )
305
+ when [ :size , 0 ]
306
+ OptSize . new ( calldata )
307
+ when [ :empty? , 0 ]
308
+ OptEmptyP . new ( calldata )
309
+ when [ :nil? , 0 ]
310
+ OptNilP . new ( calldata )
311
+ when [ :succ , 0 ]
312
+ OptSucc . new ( calldata )
313
+ when [ :! , 0 ]
314
+ OptNot . new ( calldata )
315
+ when [ :+ , 1 ]
316
+ OptPlus . new ( calldata )
317
+ when [ :- , 1 ]
318
+ OptMinus . new ( calldata )
319
+ when [ :* , 1 ]
320
+ OptMult . new ( calldata )
321
+ when [ :/ , 1 ]
322
+ OptDiv . new ( calldata )
323
+ when [ :% , 1 ]
324
+ OptMod . new ( calldata )
325
+ when [ :== , 1 ]
326
+ OptEq . new ( calldata )
327
+ when [ :!= , 1 ]
328
+ OptNEq . new ( YARV . calldata ( :== , 1 ) , calldata )
329
+ when [ :=~ , 1 ]
330
+ OptRegExpMatch2 . new ( calldata )
331
+ when [ :< , 1 ]
332
+ OptLT . new ( calldata )
333
+ when [ :<= , 1 ]
334
+ OptLE . new ( calldata )
335
+ when [ :> , 1 ]
336
+ OptGT . new ( calldata )
337
+ when [ :>= , 1 ]
338
+ OptGE . new ( calldata )
339
+ when [ :<< , 1 ]
340
+ OptLTLT . new ( calldata )
341
+ when [ :[] , 1 ]
342
+ OptAref . new ( calldata )
343
+ when [ :& , 1 ]
344
+ OptAnd . new ( calldata )
345
+ when [ :| , 1 ]
346
+ OptOr . new ( calldata )
347
+ when [ :[]= , 2 ]
348
+ OptAset . new ( calldata )
349
+ else
350
+ OptSendWithoutBlock . new ( calldata )
351
+ end
352
+ end
353
+ end
354
+ end
355
+ end
356
+
264
357
##########################################################################
265
358
# Child instruction sequence methods
266
359
##########################################################################
@@ -568,24 +661,6 @@ def opt_setinlinecache(cache)
568
661
push ( Legacy ::OptSetInlineCache . new ( cache ) )
569
662
end
570
663
571
- def opt_str_freeze ( object )
572
- if options . specialized_instruction?
573
- push ( OptStrFreeze . new ( object , YARV . calldata ( :freeze ) ) )
574
- else
575
- putstring ( object )
576
- send ( YARV . calldata ( :freeze ) )
577
- end
578
- end
579
-
580
- def opt_str_uminus ( object )
581
- if options . specialized_instruction?
582
- push ( OptStrUMinus . new ( object , YARV . calldata ( :-@ ) ) )
583
- else
584
- putstring ( object )
585
- send ( YARV . calldata ( :-@ ) )
586
- end
587
- end
588
-
589
664
def pop
590
665
push ( Pop . new )
591
666
end
@@ -625,65 +700,7 @@ def putstring(object)
625
700
end
626
701
627
702
def send ( calldata , block_iseq = nil )
628
- if options . specialized_instruction? && !block_iseq &&
629
- !calldata . flag? ( CallData ::CALL_ARGS_BLOCKARG )
630
- # Specialize the send instruction. If it doesn't have a block
631
- # attached, then we will replace it with an opt_send_without_block
632
- # and do further specializations based on the called method and the
633
- # number of arguments.
634
- case [ calldata . method , calldata . argc ]
635
- when [ :length , 0 ]
636
- push ( OptLength . new ( calldata ) )
637
- when [ :size , 0 ]
638
- push ( OptSize . new ( calldata ) )
639
- when [ :empty? , 0 ]
640
- push ( OptEmptyP . new ( calldata ) )
641
- when [ :nil? , 0 ]
642
- push ( OptNilP . new ( calldata ) )
643
- when [ :succ , 0 ]
644
- push ( OptSucc . new ( calldata ) )
645
- when [ :! , 0 ]
646
- push ( OptNot . new ( calldata ) )
647
- when [ :+ , 1 ]
648
- push ( OptPlus . new ( calldata ) )
649
- when [ :- , 1 ]
650
- push ( OptMinus . new ( calldata ) )
651
- when [ :* , 1 ]
652
- push ( OptMult . new ( calldata ) )
653
- when [ :/ , 1 ]
654
- push ( OptDiv . new ( calldata ) )
655
- when [ :% , 1 ]
656
- push ( OptMod . new ( calldata ) )
657
- when [ :== , 1 ]
658
- push ( OptEq . new ( calldata ) )
659
- when [ :!= , 1 ]
660
- push ( OptNEq . new ( YARV . calldata ( :== , 1 ) , calldata ) )
661
- when [ :=~ , 1 ]
662
- push ( OptRegExpMatch2 . new ( calldata ) )
663
- when [ :< , 1 ]
664
- push ( OptLT . new ( calldata ) )
665
- when [ :<= , 1 ]
666
- push ( OptLE . new ( calldata ) )
667
- when [ :> , 1 ]
668
- push ( OptGT . new ( calldata ) )
669
- when [ :>= , 1 ]
670
- push ( OptGE . new ( calldata ) )
671
- when [ :<< , 1 ]
672
- push ( OptLTLT . new ( calldata ) )
673
- when [ :[] , 1 ]
674
- push ( OptAref . new ( calldata ) )
675
- when [ :& , 1 ]
676
- push ( OptAnd . new ( calldata ) )
677
- when [ :| , 1 ]
678
- push ( OptOr . new ( calldata ) )
679
- when [ :[]= , 2 ]
680
- push ( OptAset . new ( calldata ) )
681
- else
682
- push ( OptSendWithoutBlock . new ( calldata ) )
683
- end
684
- else
685
- push ( Send . new ( calldata , block_iseq ) )
686
- end
703
+ push ( Send . new ( calldata , block_iseq ) )
687
704
end
688
705
689
706
def setblockparam ( index , level )
@@ -931,9 +948,11 @@ def self.from(source, options = Compiler::Options.new, parent_iseq = nil)
931
948
when :opt_setinlinecache
932
949
iseq . opt_setinlinecache ( opnds [ 0 ] )
933
950
when :opt_str_freeze
934
- iseq . opt_str_freeze ( opnds [ 0 ] )
951
+ iseq . putstring ( opnds [ 0 ] )
952
+ iseq . send ( YARV . calldata ( :freeze ) )
935
953
when :opt_str_uminus
936
- iseq . opt_str_uminus ( opnds [ 0 ] )
954
+ iseq . putstring ( opnds [ 0 ] )
955
+ iseq . send ( YARV . calldata ( :-@ ) )
937
956
when :pop
938
957
iseq . pop
939
958
when :putnil
0 commit comments