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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1031 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 :concattoarray iseq.concattoarray(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 mid = opnds[1] if RUBY_VERSION >= "3.4" mid = %i[max min hash pack pack_buffer include?][mid - 1] end iseq.newarray(opnds[0]) iseq.send(CallData.new(mid)) 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 :pushtoarraykwsplat iseq.pushtoarraykwsplat when :putchilledstring iseq.putchilledstring(opnds[0]) 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 method will create a new instruction sequence from a serialized RubyVM::InstructionSequence object.
Source
# 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
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.
Source
# 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 656 def adjuststack(number) push(AdjustStack.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 660 def anytostring push(AnyToString.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 476 def block_child_iseq(line) current = self current = current.parent_iseq while current.type == :block child_iseq("block in #{current.name}", line, :block) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 664 def branchif(label) push(BranchIf.new(label)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 668 def branchnil(label) push(BranchNil.new(label)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 672 def branchunless(label) push(BranchUnless.new(label)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 569 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 579 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 589 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 599 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 609 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 619 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 676 def checkkeyword(keyword_bits_index, keyword_index) push(CheckKeyword.new(keyword_bits_index, keyword_index)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 680 def checkmatch(type) push(CheckMatch.new(type)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 684 def checktype(type) push(CheckType.new(type)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 472 def child_iseq(name, line, type) InstructionSequence.new(name, file, line, type, self, options) end
Child instruction sequence methods
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 482 def class_child_iseq(name, line) child_iseq("<class:#{name}>", line, :class) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 309 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
This method converts our linked list of instructions into a final array and performs any other compilation steps necessary.
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 688 def concatarray push(ConcatArray.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 692 def concatstrings(number) push(ConcatStrings.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 696 def concattoarray(object) push(ConcatToArray.new(object)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 700 def defineclass(name, class_iseq, flags) push(DefineClass.new(name, class_iseq, flags)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 704 def defined(type, name, message) push(Defined.new(type, name, message)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 708 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 717 def definemethod(name, method_iseq) push(DefineMethod.new(name, method_iseq)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 721 def definesmethod(name, method_iseq) push(DefineSMethod.new(name, method_iseq)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 296 def disasm fmt = Disassembler.new fmt.enqueue(self) fmt.format! fmt.string end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 725 def dup push(Dup.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 729 def duparray(object) push(DupArray.new(object)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 733 def duphash(object) push(DupHash.new(object)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 737 def dupn(number) push(DupN.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 232 def eval InstructionSequence.iseq_load(to_a).eval end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 652 def event(name) push(name) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 741 def expandarray(length, flags) push(ExpandArray.new(length, flags)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 745 def getblockparam(index, level) push(GetBlockParam.new(index, level)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 749 def getblockparamproxy(index, level) push(GetBlockParamProxy.new(index, level)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 753 def getclassvariable(name) if RUBY_VERSION < "3.0" push(Legacy::GetClassVariable.new(name)) else push(GetClassVariable.new(name, inline_storage_for(name))) end end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 761 def getconstant(name) push(GetConstant.new(name)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 765 def getglobal(name) push(GetGlobal.new(name)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 769 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 777 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 796 def getspecial(key, type) push(GetSpecial.new(key, type)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 207 def inline_storage storage = storage_index @storage_index += 1 storage end
Source
# 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 303 def inspect "#<ISeq:#{name}@<compiled>:1 (#{line},0)-(#{line},0)>" end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 800 def intern push(Intern.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 804 def invokeblock(calldata) push(InvokeBlock.new(calldata)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 808 def invokesuper(calldata, block_iseq) push(InvokeSuper.new(calldata, block_iseq)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 812 def jump(label) push(Jump.new(label)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 633 def label Label.new end
Instruction
push methods
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 816 def leave push(Leave.new) end
Source
# 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
Source
# 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
Query methods
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 486 def method_child_iseq(name, line) child_iseq(name, line, :method) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 490 def module_child_iseq(name, line) child_iseq("<module:#{name}>", line, :class) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 820 def newarray(number) push(NewArray.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 824 def newarraykwsplat(number) push(NewArrayKwSplat.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 828 def newhash(number) push(NewHash.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 832 def newrange(exclude_end) push(NewRange.new(exclude_end)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 836 def nop push(Nop.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 840 def objtostring(calldata) push(ObjToString.new(calldata)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 844 def once(iseq, cache) push(Once.new(iseq, cache)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 848 def opt_aref_with(object, calldata) push(OptArefWith.new(object, calldata)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 852 def opt_aset_with(object, calldata) push(OptAsetWith.new(object, calldata)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 856 def opt_case_dispatch(case_dispatch_hash, else_label) push(OptCaseDispatch.new(case_dispatch_hash, else_label)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 860 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 896 def opt_getinlinecache(label, cache) push(Legacy::OptGetInlineCache.new(label, cache)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 900 def opt_setinlinecache(cache) push(Legacy::OptSetInlineCache.new(cache)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 904 def pop push(Pop.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 637 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 908 def pushtoarraykwsplat push(PushToArrayKwSplat.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 912 def putchilledstring(object) push(PutChilledString.new(object)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 916 def putnil push(PutNil.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 920 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 938 def putself push(PutSelf.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 942 def putspecialobject(object) push(PutSpecialObject.new(object)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 946 def putstring(object) push(PutString.new(object)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 950 def send(calldata, block_iseq = nil) push(Send.new(calldata, block_iseq)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 954 def setblockparam(index, level) push(SetBlockParam.new(index, level)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 958 def setclassvariable(name) if RUBY_VERSION < "3.0" push(Legacy::SetClassVariable.new(name)) else push(SetClassVariable.new(name, inline_storage_for(name))) end end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 966 def setconstant(name) push(SetConstant.new(name)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 970 def setglobal(name) push(SetGlobal.new(name)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 974 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 982 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1001 def setn(number) push(SetN.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1005 def setspecial(key) push(SetSpecial.new(key)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 494 def singleton_class_child_iseq(line) child_iseq("singleton class", line, :class) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 345 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
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1009 def splatarray(flag) push(SplatArray.new(flag)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1013 def swap push(Swap.new) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1017 def throw(type) push(Throw.new(type)) end
Source
# 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] metadata = { arg_size: argument_size, local_size: local_table.size, stack_max: stack.maximum_size, node_id: -1, node_ids: [-1] * insns.length } metadata[:parser] = :prism if RUBY_VERSION >= "3.3" # Next, return the instruction sequence as an array. [ MAGIC, versions[0], versions[1], 1, metadata, name, file, "<compiled>", line, type, local_table.names, dumped_options, catch_table.map(&:to_a), dumped ] end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 284 def to_cfg ControlFlowGraph.compile(self) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 288 def to_dfg to_cfg.to_dfg end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 292 def to_son to_dfg.to_son end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1021 def topn(number) push(TopN.new(number)) end
Source
# File lib/syntax_tree/yarv/instruction_sequence.rb, line 1025 def toregexp(options, length) push(ToRegExp.new(options, length)) end