Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 69d2dfa

Browse files
committed
Specialize in a separate pass
1 parent 2115177 commit 69d2dfa

File tree

2 files changed

+102
-94
lines changed

2 files changed

+102
-94
lines changed

lib/syntax_tree/yarv/compiler.rb

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -632,17 +632,6 @@ def visit_call(node)
632632
return
633633
end
634634
end
635-
when StringLiteral
636-
if RubyVisitor.compile(node.receiver).nil?
637-
case node.message.value
638-
when "-@"
639-
iseq.opt_str_uminus(node.receiver.parts.first.value)
640-
return
641-
when "freeze"
642-
iseq.opt_str_freeze(node.receiver.parts.first.value)
643-
return
644-
end
645-
end
646635
end
647636
end
648637

lib/syntax_tree/yarv/instruction_sequence.rb

Lines changed: 102 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)