@@ -12,8 +12,7 @@ class InstructionSequence
1212 # and other transformations like instruction specialization.
1313 class InstructionList
1414 class Node
15- attr_reader :instruction
16- attr_accessor :next_node
15+ attr_accessor :instruction , :next_node
1716
1817 def initialize ( instruction , next_node = nil )
1918 @instruction = instruction
@@ -29,11 +28,16 @@ def initialize
2928 end
3029
3130 def each
31+ return to_enum ( __method__ ) unless block_given?
32+ each_node { |node | yield node . instruction }
33+ end
34+
35+ def each_node
3236 return to_enum ( __method__ ) unless block_given?
3337 node = head_node
3438
3539 while node
36- yield node . instruction
40+ yield node
3741 node = node . next_node
3842 end
3943 end
@@ -210,7 +214,10 @@ def eval
210214 def to_a
211215 versions = RUBY_VERSION . split ( "." ) . map ( &:to_i )
212216
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.
214221 insns . each . inject ( 0 ) do |length , insn |
215222 case insn
216223 when Integer , Symbol
@@ -261,6 +268,92 @@ def to_a
261268 ]
262269 end
263270
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+
264357 ##########################################################################
265358 # Child instruction sequence methods
266359 ##########################################################################
@@ -568,24 +661,6 @@ def opt_setinlinecache(cache)
568661 push ( Legacy ::OptSetInlineCache . new ( cache ) )
569662 end
570663
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-
589664 def pop
590665 push ( Pop . new )
591666 end
@@ -625,65 +700,7 @@ def putstring(object)
625700 end
626701
627702 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 ) )
687704 end
688705
689706 def setblockparam ( index , level )
@@ -931,9 +948,11 @@ def self.from(source, options = Compiler::Options.new, parent_iseq = nil)
931948 when :opt_setinlinecache
932949 iseq . opt_setinlinecache ( opnds [ 0 ] )
933950 when :opt_str_freeze
934- iseq . opt_str_freeze ( opnds [ 0 ] )
951+ iseq . putstring ( opnds [ 0 ] )
952+ iseq . send ( YARV . calldata ( :freeze ) )
935953 when :opt_str_uminus
936- iseq . opt_str_uminus ( opnds [ 0 ] )
954+ iseq . putstring ( opnds [ 0 ] )
955+ iseq . send ( YARV . calldata ( :-@ ) )
937956 when :pop
938957 iseq . pop
939958 when :putnil
0 commit comments