class SyntaxTree::YARV::InstructionSequence
This class is meant to mirror RubyVM::InstructionSequence. It contains a list of instructions along with the metadata pertaining to them. It also functions as a builder for the instruction sequence.
Constants
- MAGIC
Attributes
This is the list of information about the arguments to this instruction sequence.
The catch table for this instruction sequence.
The source location of the instruction sequence.
The hash of names of instance and class variables pointing to the index of their associated inline storage.
The list of instructions for this instruction sequence.
The source location of the instruction sequence.
The table of local variables.
The name of the instruction sequence.
These are various compilation options provided.
The parent instruction sequence, if there is one.
An object that will track the current size of the stack and the maximum size of the stack for this instruction sequence.
The index of the next inline storage that will be created.
The type of the instruction sequence.
Public Class Methods
This method will create a new instruction sequence from a serialized RubyVM::InstructionSequence object.
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1015 def self.from(source, options = Compiler::Options.new, parent_iseq = nil) iseq = new(source[5], source[6], source[8], source[9], parent_iseq, options) # set up the labels object so that the labels are shared between the # location in the instruction sequence and the instructions that # reference them labels = Hash.new { |hash, name| hash[name] = Label.new(name) } # set up the correct argument size iseq.argument_size = source[4][:arg_size] # set up all of the locals source[10].each { |local| iseq.local_table.plain(local) } # set up the argument options iseq.argument_options.merge!(source[11]) if iseq.argument_options[:opt] iseq.argument_options[:opt].map! { |opt| labels[opt] } end # track the child block iseqs so that our catch table can point to the # correctly created iseqs block_iseqs = [] # set up all of the instructions source[13].each do |insn| # add line numbers if insn.is_a?(Integer) iseq.push(insn) next end # add events and labels if insn.is_a?(Symbol) if insn.start_with?("label_") iseq.push(labels[insn]) else iseq.push(insn) end next end # add instructions, mapped to our own instruction classes type, *opnds = insn case type when :adjuststack iseq.adjuststack(opnds[0]) when :anytostring iseq.anytostring when :branchif iseq.branchif(labels[opnds[0]]) when :branchnil iseq.branchnil(labels[opnds[0]]) when :branchunless iseq.branchunless(labels[opnds[0]]) when :checkkeyword iseq.checkkeyword(iseq.local_table.size - opnds[0] + 2, opnds[1]) when :checkmatch iseq.checkmatch(opnds[0]) when :checktype iseq.checktype(opnds[0]) when :concatarray iseq.concatarray when :concatstrings iseq.concatstrings(opnds[0]) when :defineclass iseq.defineclass(opnds[0], from(opnds[1], options, iseq), opnds[2]) when :defined iseq.defined(opnds[0], opnds[1], opnds[2]) when :definedivar iseq.definedivar(opnds[0], opnds[1], opnds[2]) when :definemethod iseq.definemethod(opnds[0], from(opnds[1], options, iseq)) when :definesmethod iseq.definesmethod(opnds[0], from(opnds[1], options, iseq)) when :dup iseq.dup when :duparray iseq.duparray(opnds[0]) when :duphash iseq.duphash(opnds[0]) when :dupn iseq.dupn(opnds[0]) when :expandarray iseq.expandarray(opnds[0], opnds[1]) when :getblockparam, :getblockparamproxy, :getlocal, :getlocal_WC_0, :getlocal_WC_1, :setblockparam, :setlocal, :setlocal_WC_0, :setlocal_WC_1 current = iseq level = 0 case type when :getlocal_WC_1, :setlocal_WC_1 level = 1 when :getblockparam, :getblockparamproxy, :getlocal, :setblockparam, :setlocal level = opnds[1] end level.times { current = current.parent_iseq } index = current.local_table.size - opnds[0] + 2 case type when :getblockparam iseq.getblockparam(index, level) when :getblockparamproxy iseq.getblockparamproxy(index, level) when :getlocal, :getlocal_WC_0, :getlocal_WC_1 iseq.getlocal(index, level) when :setblockparam iseq.setblockparam(index, level) when :setlocal, :setlocal_WC_0, :setlocal_WC_1 iseq.setlocal(index, level) end when :getclassvariable iseq.push(GetClassVariable.new(opnds[0], opnds[1])) when :getconstant iseq.getconstant(opnds[0]) when :getglobal iseq.getglobal(opnds[0]) when :getinstancevariable iseq.push(GetInstanceVariable.new(opnds[0], opnds[1])) when :getspecial iseq.getspecial(opnds[0], opnds[1]) when :intern iseq.intern when :invokeblock iseq.invokeblock(CallData.from(opnds[0])) when :invokesuper block_iseq = opnds[1] ? from(opnds[1], options, iseq) : nil iseq.invokesuper(CallData.from(opnds[0]), block_iseq) when :jump iseq.jump(labels[opnds[0]]) when :leave iseq.leave when :newarray iseq.newarray(opnds[0]) when :newarraykwsplat iseq.newarraykwsplat(opnds[0]) when :newhash iseq.newhash(opnds[0]) when :newrange iseq.newrange(opnds[0]) when :nop iseq.nop when :objtostring iseq.objtostring(CallData.from(opnds[0])) when :once iseq.once(from(opnds[0], options, iseq), opnds[1]) when :opt_and, :opt_aref, :opt_aset, :opt_div, :opt_empty_p, :opt_eq, :opt_ge, :opt_gt, :opt_le, :opt_length, :opt_lt, :opt_ltlt, :opt_minus, :opt_mod, :opt_mult, :opt_nil_p, :opt_not, :opt_or, :opt_plus, :opt_regexpmatch2, :opt_send_without_block, :opt_size, :opt_succ iseq.send(CallData.from(opnds[0]), nil) when :opt_aref_with iseq.opt_aref_with(opnds[0], CallData.from(opnds[1])) when :opt_aset_with iseq.opt_aset_with(opnds[0], CallData.from(opnds[1])) when :opt_case_dispatch hash = opnds[0] .each_slice(2) .to_h .transform_values { |value| labels[value] } iseq.opt_case_dispatch(hash, labels[opnds[1]]) when :opt_getconstant_path iseq.opt_getconstant_path(opnds[0]) when :opt_getinlinecache iseq.opt_getinlinecache(labels[opnds[0]], opnds[1]) when :opt_newarray_max iseq.newarray(opnds[0]) iseq.send(YARV.calldata(:max)) when :opt_newarray_min iseq.newarray(opnds[0]) iseq.send(YARV.calldata(:min)) when :opt_newarray_send iseq.newarray(opnds[0]) iseq.send(CallData.new(opnds[1])) when :opt_neq iseq.push( OptNEq.new(CallData.from(opnds[0]), CallData.from(opnds[1])) ) when :opt_setinlinecache iseq.opt_setinlinecache(opnds[0]) when :opt_str_freeze iseq.putstring(opnds[0]) iseq.send(YARV.calldata(:freeze)) when :opt_str_uminus iseq.putstring(opnds[0]) iseq.send(YARV.calldata(:-@)) when :pop iseq.pop when :putnil iseq.putnil when :putobject iseq.putobject(opnds[0]) when :putobject_INT2FIX_0_ iseq.putobject(0) when :putobject_INT2FIX_1_ iseq.putobject(1) when :putself iseq.putself when :putstring iseq.putstring(opnds[0]) when :putspecialobject iseq.putspecialobject(opnds[0]) when :send block_iseq = opnds[1] ? from(opnds[1], options, iseq) : nil block_iseqs << block_iseq if block_iseq iseq.send(CallData.from(opnds[0]), block_iseq) when :setclassvariable iseq.push(SetClassVariable.new(opnds[0], opnds[1])) when :setconstant iseq.setconstant(opnds[0]) when :setglobal iseq.setglobal(opnds[0]) when :setinstancevariable iseq.push(SetInstanceVariable.new(opnds[0], opnds[1])) when :setn iseq.setn(opnds[0]) when :setspecial iseq.setspecial(opnds[0]) when :splatarray iseq.splatarray(opnds[0]) when :swap iseq.swap when :throw iseq.throw(opnds[0]) when :topn iseq.topn(opnds[0]) when :toregexp iseq.toregexp(opnds[0], opnds[1]) else raise "Unknown instruction type: #{type}" end end # set up the catch table source[12].each do |entry| case entry[0] when :break if entry[1] break_iseq = block_iseqs.find do |block_iseq| block_iseq.name == entry[1][5] && block_iseq.file == entry[1][6] && block_iseq.line == entry[1][8] end iseq.catch_break( break_iseq || from(entry[1], options, iseq), labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) else iseq.catch_break( nil, labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) end when :ensure iseq.catch_ensure( from(entry[1], options, iseq), labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) when :next iseq.catch_next( labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) when :rescue iseq.catch_rescue( from(entry[1], options, iseq), labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) when :redo iseq.catch_redo( labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) when :retry iseq.catch_retry( labels[entry[2]], labels[entry[3]], labels[entry[4]], entry[5] ) else raise "unknown catch type: #{entry[0]}" end end iseq.compile! if iseq.type == :top iseq end
This provides a handle to the rb_iseq_load function, which allows you to pass a serialized iseq to Ruby and have it return a RubyVM::InstructionSequence object.
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 13 def self.iseq_load(iseq) require "fiddle" @iseq_load_function ||= Fiddle::Function.new( Fiddle::Handle::DEFAULT["rb_iseq_load"], [Fiddle::TYPE_VOIDP] * 3, Fiddle::TYPE_VOIDP ) Fiddle.dlunwrap(@iseq_load_function.call(Fiddle.dlwrap(iseq), 0, nil)) rescue LoadError raise "Could not load the Fiddle library" rescue NameError raise "Unable to find rb_iseq_load" rescue Fiddle::DLError raise "Unable to perform a dynamic load" end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 168 def initialize( name, file, line, type, parent_iseq = nil, options = Compiler::Options.new ) @name = name @file = file @line = line @type = type @parent_iseq = parent_iseq @argument_size = 0 @argument_options = {} @catch_table = [] @local_table = LocalTable.new @inline_storages = {} @insns = InstructionList.new @storage_index = 0 @stack = Stack.new @options = options end
Public Instance Methods
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 652 def adjuststack(number) push(AdjustStack.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 656 def anytostring push(AnyToString.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 472 def block_child_iseq(line) current = self current = current.parent_iseq while current.type == :block child_iseq("block in #{current.name}", line, :block) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 660 def branchif(label) push(BranchIf.new(label)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 664 def branchnil(label) push(BranchNil.new(label)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 668 def branchunless(label) push(BranchUnless.new(label)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 565 def catch_break(iseq, begin_label, end_label, exit_label, restore_sp) catch_table << CatchBreak.new( iseq, begin_label, end_label, exit_label, restore_sp ) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 575 def catch_ensure(iseq, begin_label, end_label, exit_label, restore_sp) catch_table << CatchEnsure.new( iseq, begin_label, end_label, exit_label, restore_sp ) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 585 def catch_next(begin_label, end_label, exit_label, restore_sp) catch_table << CatchNext.new( nil, begin_label, end_label, exit_label, restore_sp ) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 595 def catch_redo(begin_label, end_label, exit_label, restore_sp) catch_table << CatchRedo.new( nil, begin_label, end_label, exit_label, restore_sp ) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 605 def catch_rescue(iseq, begin_label, end_label, exit_label, restore_sp) catch_table << CatchRescue.new( iseq, begin_label, end_label, exit_label, restore_sp ) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 615 def catch_retry(begin_label, end_label, exit_label, restore_sp) catch_table << CatchRetry.new( nil, begin_label, end_label, exit_label, restore_sp ) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 672 def checkkeyword(keyword_bits_index, keyword_index) push(CheckKeyword.new(keyword_bits_index, keyword_index)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 676 def checkmatch(type) push(CheckMatch.new(type)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 680 def checktype(type) push(CheckType.new(type)) end
Child instruction sequence methods
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 468 def child_iseq(name, line, type) InstructionSequence.new(name, file, line, type, self, options) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 478 def class_child_iseq(name, line) child_iseq("<class:#{name}>", line, :class) end
This method converts our linked list of instructions into a final array and performs any other compilation steps necessary.
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 305 def compile! specialize_instructions! if options.specialized_instruction? catch_table.each do |catch_entry| if !catch_entry.is_a?(CatchBreak) && catch_entry.iseq catch_entry.iseq.compile! end end 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
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 684 def concatarray push(ConcatArray.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 688 def concatstrings(number) push(ConcatStrings.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 692 def defineclass(name, class_iseq, flags) push(DefineClass.new(name, class_iseq, flags)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 696 def defined(type, name, message) push(Defined.new(type, name, message)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 700 def definedivar(name, cache, message) if RUBY_VERSION < "3.3" push(PutNil.new) push(Defined.new(Defined::TYPE_IVAR, name, message)) else push(DefinedIVar.new(name, cache, message)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 709 def definemethod(name, method_iseq) push(DefineMethod.new(name, method_iseq)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 713 def definesmethod(name, method_iseq) push(DefineSMethod.new(name, method_iseq)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 292 def disasm fmt = Disassembler.new fmt.enqueue(self) fmt.format! fmt.string end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 717 def dup push(Dup.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 721 def duparray(object) push(DupArray.new(object)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 725 def duphash(object) push(DupHash.new(object)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 729 def dupn(number) push(DupN.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 232 def eval InstructionSequence.iseq_load(to_a).eval end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 648 def event(name) push(name) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 733 def expandarray(length, flags) push(ExpandArray.new(length, flags)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 737 def getblockparam(index, level) push(GetBlockParam.new(index, level)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 741 def getblockparamproxy(index, level) push(GetBlockParamProxy.new(index, level)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 745 def getclassvariable(name) if RUBY_VERSION < "3.0" push(Legacy::GetClassVariable.new(name)) else push(GetClassVariable.new(name, inline_storage_for(name))) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 753 def getconstant(name) push(GetConstant.new(name)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 757 def getglobal(name) push(GetGlobal.new(name)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 761 def getinstancevariable(name) if RUBY_VERSION < "3.2" push(GetInstanceVariable.new(name, inline_storage_for(name))) else push(GetInstanceVariable.new(name, inline_storage)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 769 def getlocal(index, level) if options.operands_unification? # Specialize the getlocal instruction based on the level of the # local variable. If it's 0 or 1, then there's a specialized # instruction that will look at the current scope or the parent # scope, respectively, and requires fewer operands. case level when 0 push(GetLocalWC0.new(index)) when 1 push(GetLocalWC1.new(index)) else push(GetLocal.new(index, level)) end else push(GetLocal.new(index, level)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 788 def getspecial(key, type) push(GetSpecial.new(key, type)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 207 def inline_storage storage = storage_index @storage_index += 1 storage end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 213 def inline_storage_for(name) inline_storages[name] = inline_storage unless inline_storages.key?(name) inline_storages[name] end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 299 def inspect "#<ISeq:#{name}@<compiled>:1 (#{line},0)-(#{line},0)>" end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 792 def intern push(Intern.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 796 def invokeblock(calldata) push(InvokeBlock.new(calldata)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 800 def invokesuper(calldata, block_iseq) push(InvokeSuper.new(calldata, block_iseq)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 804 def jump(label) push(Jump.new(label)) end
Instruction
push methods
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 629 def label Label.new end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 808 def leave push(Leave.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 219 def length insns .each .inject(0) do |sum, insn| case insn when Integer, Label, Symbol sum else sum + insn.length end end end
Query methods
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 199 def local_variable(name, level = 0) if (lookup = local_table.find(name, level)) lookup elsif parent_iseq parent_iseq.local_variable(name, level + 1) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 482 def method_child_iseq(name, line) child_iseq(name, line, :method) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 486 def module_child_iseq(name, line) child_iseq("<module:#{name}>", line, :class) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 812 def newarray(number) push(NewArray.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 816 def newarraykwsplat(number) push(NewArrayKwSplat.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 820 def newhash(number) push(NewHash.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 824 def newrange(exclude_end) push(NewRange.new(exclude_end)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 828 def nop push(Nop.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 832 def objtostring(calldata) push(ObjToString.new(calldata)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 836 def once(iseq, cache) push(Once.new(iseq, cache)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 840 def opt_aref_with(object, calldata) push(OptArefWith.new(object, calldata)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 844 def opt_aset_with(object, calldata) push(OptAsetWith.new(object, calldata)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 848 def opt_case_dispatch(case_dispatch_hash, else_label) push(OptCaseDispatch.new(case_dispatch_hash, else_label)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 852 def opt_getconstant_path(names) if RUBY_VERSION < "3.2" || !options.inline_const_cache? cache = nil cache_filled_label = nil if options.inline_const_cache? cache = inline_storage cache_filled_label = label opt_getinlinecache(cache_filled_label, cache) if names[0] == :"" names.shift pop putobject(Object) end elsif names[0] == :"" names.shift putobject(Object) else putnil end names.each_with_index do |name, index| putobject(index == 0) getconstant(name) end if options.inline_const_cache? opt_setinlinecache(cache) push(cache_filled_label) end else push(OptGetConstantPath.new(names)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 888 def opt_getinlinecache(label, cache) push(Legacy::OptGetInlineCache.new(label, cache)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 892 def opt_setinlinecache(cache) push(Legacy::OptSetInlineCache.new(cache)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 896 def pop push(Pop.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 633 def push(value) node = insns.push(value) case value when Array, Integer, Symbol value when Label value.node = node value else stack.change_by(-value.pops + value.pushes) value end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 900 def putnil push(PutNil.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 904 def putobject(object) if options.operands_unification? # Specialize the putobject instruction based on the value of the # object. If it's 0 or 1, then there's a specialized instruction # that will push the object onto the stack and requires fewer # operands. if object.eql?(0) push(PutObjectInt2Fix0.new) elsif object.eql?(1) push(PutObjectInt2Fix1.new) else push(PutObject.new(object)) end else push(PutObject.new(object)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 922 def putself push(PutSelf.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 926 def putspecialobject(object) push(PutSpecialObject.new(object)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 930 def putstring(object) push(PutString.new(object)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 934 def send(calldata, block_iseq = nil) push(Send.new(calldata, block_iseq)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 938 def setblockparam(index, level) push(SetBlockParam.new(index, level)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 942 def setclassvariable(name) if RUBY_VERSION < "3.0" push(Legacy::SetClassVariable.new(name)) else push(SetClassVariable.new(name, inline_storage_for(name))) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 950 def setconstant(name) push(SetConstant.new(name)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 954 def setglobal(name) push(SetGlobal.new(name)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 958 def setinstancevariable(name) if RUBY_VERSION < "3.2" push(SetInstanceVariable.new(name, inline_storage_for(name))) else push(SetInstanceVariable.new(name, inline_storage)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 966 def setlocal(index, level) if options.operands_unification? # Specialize the setlocal instruction based on the level of the # local variable. If it's 0 or 1, then there's a specialized # instruction that will write to the current scope or the parent # scope, respectively, and requires fewer operands. case level when 0 push(SetLocalWC0.new(index)) when 1 push(SetLocalWC1.new(index)) else push(SetLocal.new(index, level)) end else push(SetLocal.new(index, level)) end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 985 def setn(number) push(SetN.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 989 def setspecial(key) push(SetSpecial.new(key)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 490 def singleton_class_child_iseq(line) child_iseq("singleton class", line, :class) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 341 def specialize_instructions! insns.each_node do |node, value| case value when NewArray next unless node.next_node next_node = node.next_node next unless next_node.value.is_a?(Send) next if next_node.value.block_iseq calldata = next_node.value.calldata next unless calldata.flags == CallData::CALL_ARGS_SIMPLE next unless calldata.argc == 0 case calldata.method when :min node.value = if RUBY_VERSION < "3.3" Legacy::OptNewArrayMin.new(value.number) else OptNewArraySend.new(value.number, :min) end node.next_node = next_node.next_node when :max node.value = if RUBY_VERSION < "3.3" Legacy::OptNewArrayMax.new(value.number) else OptNewArraySend.new(value.number, :max) end node.next_node = next_node.next_node when :hash next if RUBY_VERSION < "3.3" node.value = OptNewArraySend.new(value.number, :hash) node.next_node = next_node.next_node end when PutObject, PutString next unless node.next_node next if value.is_a?(PutObject) && !value.object.is_a?(String) next_node = node.next_node next unless next_node.value.is_a?(Send) next if next_node.value.block_iseq calldata = next_node.value.calldata next unless calldata.flags == CallData::CALL_ARGS_SIMPLE next unless calldata.argc == 0 case calldata.method when :freeze node.value = OptStrFreeze.new(value.object, calldata) node.next_node = next_node.next_node when :-@ node.value = OptStrUMinus.new(value.object, calldata) node.next_node = next_node.next_node end when Send calldata = value.calldata 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 # the number of arguments. node.value = case [calldata.method, calldata.argc] when [:length, 0] OptLength.new(calldata) when [:size, 0] OptSize.new(calldata) when [:empty?, 0] OptEmptyP.new(calldata) when [:nil?, 0] OptNilP.new(calldata) when [:succ, 0] OptSucc.new(calldata) when [:!, 0] OptNot.new(calldata) when [:+, 1] OptPlus.new(calldata) when [:-, 1] OptMinus.new(calldata) when [:*, 1] OptMult.new(calldata) when [:/, 1] OptDiv.new(calldata) when [:%, 1] OptMod.new(calldata) when [:==, 1] OptEq.new(calldata) when [:!=, 1] OptNEq.new(YARV.calldata(:==, 1), calldata) when [:=~, 1] OptRegExpMatch2.new(calldata) when [:<, 1] OptLT.new(calldata) when [:<=, 1] OptLE.new(calldata) when [:>, 1] OptGT.new(calldata) when [:>=, 1] OptGE.new(calldata) when [:<<, 1] OptLTLT.new(calldata) when [:[], 1] OptAref.new(calldata) when [:&, 1] OptAnd.new(calldata) when [:|, 1] OptOr.new(calldata) when [:[]=, 2] OptAset.new(calldata) else OptSendWithoutBlock.new(calldata) end end end end end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 993 def splatarray(flag) push(SplatArray.new(flag)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 997 def swap push(Swap.new) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1001 def throw(type) push(Throw.new(type)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 236 def to_a versions = RUBY_VERSION.split(".").map(&:to_i) # Dump all of the instructions into a flat list. dumped = insns.map do |insn| case insn when Integer, Symbol insn when Label insn.name else insn.to_a(self) end end dumped_options = argument_options.dup dumped_options[:opt].map!(&:name) if dumped_options[:opt] # Next, return the instruction sequence as an array. [ MAGIC, versions[0], versions[1], 1, { arg_size: argument_size, local_size: local_table.size, stack_max: stack.maximum_size, node_id: -1, node_ids: [-1] * insns.length }, name, file, "<compiled>", line, type, local_table.names, dumped_options, catch_table.map(&:to_a), dumped ] end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 280 def to_cfg ControlFlowGraph.compile(self) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 284 def to_dfg to_cfg.to_dfg end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 288 def to_son to_dfg.to_son end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1005 def topn(number) push(TopN.new(number)) end
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1009 def toregexp(options, length) push(ToRegExp.new(options, length)) end