Skip to content
Prev Previous commit
Next Next commit
Add an entire compile! step
  • Loading branch information
kddnewton committed Nov 29, 2022
commit 70064564221d38748366abc264368cbb5f8042b3
1 change: 0 additions & 1 deletion lib/syntax_tree/yarv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ def self.compile(source, options = Compiler::Options.new)
def self.interpret(source, options = Compiler::Options.new)
iseq = RubyVM::InstructionSequence.compile(source, **options)
iseq = InstructionSequence.from(iseq.to_a)
iseq.specialize_instructions!
VM.new.run_top_frame(iseq)
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/syntax_tree/yarv/bf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def compile
end

iseq.leave
iseq.compile!
iseq
end

Expand Down
4 changes: 4 additions & 0 deletions lib/syntax_tree/yarv/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,7 @@ def visit_program(node)
node.location,
options
)

with_child_iseq(top_iseq) do
visit_all(preexes)

Expand All @@ -1372,6 +1373,9 @@ def visit_program(node)

iseq.leave
end

top_iseq.compile!
top_iseq
end

def visit_qsymbols(node)
Expand Down
3 changes: 1 addition & 2 deletions lib/syntax_tree/yarv/disassembler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def disassemble(iseq)
clauses = {}
clause = []

iseq.to_a
iseq.insns.each do |insn|
case insn
when InstructionSequence::Label
Expand Down Expand Up @@ -192,7 +191,7 @@ def disassemble(iseq)
Assign(VarField(target), value)
end
else
raise "Unknown instruction #{insn[0]}"
raise "Unknown instruction #{insn}"
end
end

Expand Down
103 changes: 62 additions & 41 deletions lib/syntax_tree/yarv/instruction_sequence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,24 +232,7 @@ def eval
def to_a
versions = RUBY_VERSION.split(".").map(&:to_i)

# First, handle any compilation options that we need to.
specialize_instructions! if options.specialized_instruction?
peephole_optimize! if options.peephole_optimization?

# Next, set it up so that all of the labels get their correct name.
length = 0
insns.each do |insn|
case insn
when Integer, Symbol
# skip
when Label
insn.patch!(:"label_#{length}")
else
length += insn.length
end
end

# Next, dump all of the instructions into a flat list.
# Dump all of the instructions into a flat list.
dumped =
insns.map do |insn|
case insn
Expand Down Expand Up @@ -288,6 +271,65 @@ def to_a
]
end

def disasm
output = StringIO.new
output << "== disasm: #<ISeq:#{name}@<compiled>:1 (#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column})> (catch: FALSE)\n"

length = 0
events = []

insns.each do |insn|
case insn
when Integer
# skip
when Symbol
events << insn
when Label
# skip
else
output << "%04d " % length
output << insn.disasm(self)
output << "\n"
end

length += insn.length
end

output.string
end

# This method converts our linked list of instructions into a final array
# and performs any other compilation steps necessary.
def compile!
specialize_instructions! if options.specialized_instruction?

length = 0
insns.each do |insn|
case insn
when Integer, Symbol
# skip
when Label
insn.patch!(:"label_#{length}")
when DefineClass
insn.class_iseq.compile!
length += insn.length
when DefineMethod, DefineSMethod
insn.method_iseq.compile!
length += insn.length
when InvokeSuper, Send
insn.block_iseq.compile! if insn.block_iseq
length += insn.length
when Once
insn.iseq.compile!
length += insn.length
else
length += insn.length
end
end

@insns = insns.to_a
end

def specialize_instructions!
insns.each_node do |node, value|
case value
Expand Down Expand Up @@ -333,8 +375,7 @@ def specialize_instructions!
when Send
calldata = value.calldata

if !value.block_iseq &&
!calldata.flag?(CallData::CALL_ARGS_BLOCKARG)
if !value.block_iseq && !calldata.flag?(CallData::CALL_ARGS_BLOCKARG)
# Specialize the send instruction. If it doesn't have a block
# attached, then we will replace it with an opt_send_without_block
# and do further specializations based on the called method and
Expand Down Expand Up @@ -395,27 +436,6 @@ def specialize_instructions!
end
end

def peephole_optimize!
# insns.each_node do |node, value|
# case value
# when Jump
# # jump LABEL
# # ...
# # LABEL:
# # leave
# # =>
# # leave
# # ...
# # LABEL:
# # leave
# # case value.label.node.next_node&.value
# # when Leave
# # node.value = Leave.new
# # end
# end
# end
end

##########################################################################
# Child instruction sequence methods
##########################################################################
Expand Down Expand Up @@ -1164,6 +1184,7 @@ def self.from(source, options = Compiler::Options.new, parent_iseq = nil)
end
end

iseq.compile! if iseq.type == :top
iseq
end
end
Expand Down
43 changes: 43 additions & 0 deletions lib/syntax_tree/yarv/instructions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ def initialize(
@kw_arg = kw_arg
end

def disasm
flag_names = []
flag_names << :ARGS_SPLAT if flag?(CALL_ARGS_SPLAT)
flag_names << :ARGS_BLOCKARG if flag?(CALL_ARGS_BLOCKARG)
flag_names << :FCALL if flag?(CALL_FCALL)
flag_names << :VCALL if flag?(CALL_VCALL)
flag_names << :ARGS_SIMPLE if flag?(CALL_ARGS_SIMPLE)
flag_names << :BLOCKISEQ if flag?(CALL_BLOCKISEQ)
flag_names << :KWARG if flag?(CALL_KWARG)
flag_names << :KW_SPLAT if flag?(CALL_KW_SPLAT)
flag_names << :TAILCALL if flag?(CALL_TAILCALL)
flag_names << :SUPER if flag?(CALL_SUPER)
flag_names << :ZSUPER if flag?(CALL_ZSUPER)
flag_names << :OPT_SEND if flag?(CALL_OPT_SEND)
flag_names << :KW_SPLAT_MUT if flag?(CALL_KW_SPLAT_MUT)

"<calldata!mid:#{method}, argc:#{argc}, #{flag_names.join("|")}>"
end

def flag?(mask)
(flags & mask) > 0
end
Expand Down Expand Up @@ -1783,6 +1802,10 @@ def call(vm)
# ~~~
#
class Leave
def disasm(_iseq)
"leave"
end

def to_a(_iseq)
[:leave]
end
Expand Down Expand Up @@ -2973,6 +2996,10 @@ def initialize(calldata)
@calldata = calldata
end

def disasm(_iseq)
"%-38s %s" % ["opt_mult", calldata.disasm]
end

def to_a(_iseq)
[:opt_mult, calldata.to_h]
end
Expand Down Expand Up @@ -3288,6 +3315,10 @@ def initialize(calldata)
@calldata = calldata
end

def disasm(iseq)
"%-38s %s" % ["opt_plus", calldata.disasm]
end

def to_a(_iseq)
[:opt_plus, calldata.to_h]
end
Expand Down Expand Up @@ -3670,6 +3701,10 @@ def initialize(object)
@object = object
end

def disasm(_iseq)
"%-38s %s" % ["putobject", object.inspect]
end

def to_a(_iseq)
[:putobject, object]
end
Expand Down Expand Up @@ -3708,6 +3743,10 @@ def call(vm)
# ~~~
#
class PutObjectInt2Fix0
def disasm(_iseq)
"putobject_INT2FIX_0_"
end

def to_a(_iseq)
[:putobject_INT2FIX_0_]
end
Expand Down Expand Up @@ -3746,6 +3785,10 @@ def call(vm)
# ~~~
#
class PutObjectInt2Fix1
def disasm(_iseq)
"putobject_INT2FIX_1_"
end

def to_a(_iseq)
[:putobject_INT2FIX_1_]
end
Expand Down