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

Commit da1e466

Browse files
committed
Support the tailcall_optimization flag
1 parent 4631b5c commit da1e466

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

lib/syntax_tree/yarv/compiler.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,23 @@ def initialize(
5454
frozen_string_literal: false,
5555
inline_const_cache: true,
5656
operands_unification: true,
57-
specialized_instruction: true
57+
specialized_instruction: true,
58+
tailcall_optimization: false
5859
)
5960
@frozen_string_literal = frozen_string_literal
6061
@inline_const_cache = inline_const_cache
6162
@operands_unification = operands_unification
6263
@specialized_instruction = specialized_instruction
64+
@tailcall_optimization = tailcall_optimization
6365
end
6466

6567
def to_hash
6668
{
6769
frozen_string_literal: @frozen_string_literal,
6870
inline_const_cache: @inline_const_cache,
6971
operands_unification: @operands_unification,
70-
specialized_instruction: @specialized_instruction
72+
specialized_instruction: @specialized_instruction,
73+
tailcall_optimization: @tailcall_optimization
7174
}
7275
end
7376

@@ -90,6 +93,10 @@ def operands_unification?
9093
def specialized_instruction?
9194
@specialized_instruction
9295
end
96+
97+
def tailcall_optimization?
98+
@tailcall_optimization
99+
end
93100
end
94101

95102
# This visitor is responsible for converting Syntax Tree nodes into their
@@ -716,12 +723,17 @@ def visit_call(node)
716723
end
717724
end
718725

726+
# Track whether or not this is a method call on a block proxy receiver.
727+
# If it is, we can potentially do tailcall optimizations on it.
728+
block_receiver = false
729+
719730
if node.receiver
720731
if node.receiver.is_a?(VarRef)
721732
lookup = iseq.local_variable(node.receiver.value.value.to_sym)
722733

723734
if lookup.local.is_a?(LocalTable::BlockLocal)
724735
iseq.getblockparamproxy(lookup.index, lookup.level)
736+
block_receiver = true
725737
else
726738
visit(node.receiver)
727739
end
@@ -752,6 +764,7 @@ def visit_call(node)
752764
when ArgsForward
753765
flag |= CallData::CALL_ARGS_SPLAT
754766
flag |= CallData::CALL_ARGS_BLOCKARG
767+
flag |= CallData::CALL_TAILCALL if options.tailcall_optimization?
755768

756769
lookup = iseq.local_table.find(:*)
757770
iseq.getlocal(lookup.index, lookup.level)
@@ -768,9 +781,22 @@ def visit_call(node)
768781
end
769782

770783
block_iseq = visit(node.block) if node.block
784+
785+
# If there's no block and we don't already have any special flags set,
786+
# then we can safely call this simple arguments. Note that has to be the
787+
# first flag we set after looking at the arguments to get the flags
788+
# correct.
771789
flag |= CallData::CALL_ARGS_SIMPLE if block_iseq.nil? && flag == 0
790+
791+
# If there's no receiver, then this is an "fcall".
772792
flag |= CallData::CALL_FCALL if node.receiver.nil?
773793

794+
# If we're calling a method on the passed block object and we have
795+
# tailcall optimizations turned on, then we can set the tailcall flag.
796+
if block_receiver && options.tailcall_optimization?
797+
flag |= CallData::CALL_TAILCALL
798+
end
799+
774800
iseq.send(
775801
YARV.calldata(node.message.value.to_sym, argc, flag),
776802
block_iseq

test/compiler_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,14 +433,14 @@ class CompilerTest < Minitest::Test
433433
YARV::Compiler::Options.new(operands_unification: false),
434434
YARV::Compiler::Options.new(specialized_instruction: false),
435435
YARV::Compiler::Options.new(inline_const_cache: false),
436-
YARV::Compiler::Options.new(operands_unification: false, specialized_instruction: false)
436+
YARV::Compiler::Options.new(tailcall_optimization: true)
437437
]
438438

439439
OPTIONS.each do |options|
440-
suffix = options.inspect
440+
suffix = options.to_hash.map { |k, v| "#{k}=#{v}" }.join("&")
441441

442442
CASES.each do |source|
443-
define_method(:"test_#{source}_#{suffix}") do
443+
define_method(:"test_#{source}_(#{suffix})") do
444444
assert_compiles(source, options)
445445
end
446446
end

0 commit comments

Comments
 (0)