Class: SyntaxTree::YARV::InstructionSequence
- Inherits:
-
Object
- Object
- SyntaxTree::YARV::InstructionSequence
- Defined in:
- lib/syntax_tree/yarv/instruction_sequence.rb
Overview
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.
Defined Under Namespace
Classes: CatchBreak, CatchEnsure, CatchEntry, CatchNext, CatchRedo, CatchRescue, CatchRetry, InstructionList, Label, Stack
Constant Summary collapse
- MAGIC =
"YARVInstructionSequence/SimpleDataFormat"- ISEQ_LOAD =
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.
begin Fiddle::Function.new( Fiddle::Handle::DEFAULT["rb_iseq_load"], [Fiddle::TYPE_VOIDP] * 3, Fiddle::TYPE_VOIDP ) rescue NameError, Fiddle::DLError end
Instance Attribute Summary collapse
-
#argument_options ⇒ Object
readonly
Returns the value of attribute argument_options.
-
#argument_size ⇒ Object
This is the list of information about the arguments to this instruction sequence.
-
#catch_table ⇒ Object
readonly
The catch table for this instruction sequence.
-
#file ⇒ Object
readonly
The source location of the instruction sequence.
-
#inline_storages ⇒ Object
readonly
The hash of names of instance and class variables pointing to the index of their associated inline storage.
-
#insns ⇒ Object
readonly
The list of instructions for this instruction sequence.
-
#line ⇒ Object
readonly
The source location of the instruction sequence.
-
#local_table ⇒ Object
readonly
The table of local variables.
-
#name ⇒ Object
readonly
The name of the instruction sequence.
-
#options ⇒ Object
readonly
These are various compilation options provided.
-
#parent_iseq ⇒ Object
readonly
The parent instruction sequence, if there is one.
-
#stack ⇒ Object
readonly
An object that will track the current size of the stack and the maximum size of the stack for this instruction sequence.
-
#storage_index ⇒ Object
readonly
The index of the next inline storage that will be created.
-
#type ⇒ Object
readonly
The type of the instruction sequence.
Class Method Summary collapse
-
.from(source, options = Compiler::Options.new, parent_iseq = nil) ⇒ Object
This method will create a new instruction sequence from a serialized RubyVM::InstructionSequence object.
Instance Method Summary collapse
- #adjuststack(number) ⇒ Object
- #anytostring ⇒ Object
- #block_child_iseq(line) ⇒ Object
- #branchif(label) ⇒ Object
- #branchnil(label) ⇒ Object
- #branchunless(label) ⇒ Object
- #catch_break(iseq, begin_label, end_label, exit_label, restore_sp) ⇒ Object
- #catch_ensure(iseq, begin_label, end_label, exit_label, restore_sp) ⇒ Object
- #catch_next(begin_label, end_label, exit_label, restore_sp) ⇒ Object
- #catch_redo(begin_label, end_label, exit_label, restore_sp) ⇒ Object
- #catch_rescue(iseq, begin_label, end_label, exit_label, restore_sp) ⇒ Object
- #catch_retry(begin_label, end_label, exit_label, restore_sp) ⇒ Object
- #checkkeyword(keyword_bits_index, keyword_index) ⇒ Object
- #checkmatch(type) ⇒ Object
- #checktype(type) ⇒ Object
-
#child_iseq(name, line, type) ⇒ Object
Child instruction sequence methods.
- #class_child_iseq(name, line) ⇒ Object
-
#compile! ⇒ Object
This method converts our linked list of instructions into a final array and performs any other compilation steps necessary.
- #concatarray ⇒ Object
- #concatstrings(number) ⇒ Object
- #defineclass(name, class_iseq, flags) ⇒ Object
- #defined(type, name, message) ⇒ Object
- #definemethod(name, method_iseq) ⇒ Object
- #definesmethod(name, method_iseq) ⇒ Object
- #disasm ⇒ Object
- #dup ⇒ Object
- #duparray(object) ⇒ Object
- #duphash(object) ⇒ Object
- #dupn(number) ⇒ Object
- #eval ⇒ Object
- #event(name) ⇒ Object
- #expandarray(length, flags) ⇒ Object
- #getblockparam(index, level) ⇒ Object
- #getblockparamproxy(index, level) ⇒ Object
- #getclassvariable(name) ⇒ Object
- #getconstant(name) ⇒ Object
- #getglobal(name) ⇒ Object
- #getinstancevariable(name) ⇒ Object
- #getlocal(index, level) ⇒ Object
- #getspecial(key, type) ⇒ Object
-
#initialize(name, file, line, type, parent_iseq = nil, options = Compiler::Options.new) ⇒ InstructionSequence
constructor
A new instance of InstructionSequence.
- #inline_storage ⇒ Object
- #inline_storage_for(name) ⇒ Object
- #intern ⇒ Object
- #invokeblock(calldata) ⇒ Object
- #invokesuper(calldata, block_iseq) ⇒ Object
- #jump(label) ⇒ Object
-
#label ⇒ Object
Instruction push methods.
- #leave ⇒ Object
- #length ⇒ Object
-
#local_variable(name, level = 0) ⇒ Object
Query methods.
- #method_child_iseq(name, line) ⇒ Object
- #module_child_iseq(name, line) ⇒ Object
- #newarray(number) ⇒ Object
- #newarraykwsplat(number) ⇒ Object
- #newhash(number) ⇒ Object
- #newrange(exclude_end) ⇒ Object
- #nop ⇒ Object
- #objtostring(calldata) ⇒ Object
- #once(iseq, cache) ⇒ Object
- #opt_aref_with(object, calldata) ⇒ Object
- #opt_aset_with(object, calldata) ⇒ Object
- #opt_case_dispatch(case_dispatch_hash, else_label) ⇒ Object
- #opt_getconstant_path(names) ⇒ Object
- #opt_getinlinecache(label, cache) ⇒ Object
- #opt_setinlinecache(cache) ⇒ Object
- #pop ⇒ Object
- #push(value) ⇒ Object
- #putnil ⇒ Object
- #putobject(object) ⇒ Object
- #putself ⇒ Object
- #putspecialobject(object) ⇒ Object
- #putstring(object) ⇒ Object
- #send(calldata, block_iseq = nil) ⇒ Object
- #setblockparam(index, level) ⇒ Object
- #setclassvariable(name) ⇒ Object
- #setconstant(name) ⇒ Object
- #setglobal(name) ⇒ Object
- #setinstancevariable(name) ⇒ Object
- #setlocal(index, level) ⇒ Object
- #setn(number) ⇒ Object
- #setspecial(key) ⇒ Object
- #singleton_class_child_iseq(line) ⇒ Object
- #specialize_instructions! ⇒ Object
- #splatarray(flag) ⇒ Object
- #swap ⇒ Object
- #throw(type) ⇒ Object
- #to_a ⇒ Object
- #topn(number) ⇒ Object
- #toregexp(options, length) ⇒ Object
Constructor Details
#initialize(name, file, line, type, parent_iseq = nil, options = Compiler::Options.new) ⇒ InstructionSequence
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 159 def initialize( name, file, line, type, parent_iseq = nil, = Compiler::Options.new ) @name = name @file = file @line = line @type = type @parent_iseq = parent_iseq @argument_size = 0 = {} @catch_table = [] @local_table = LocalTable.new @inline_storages = {} @insns = InstructionList.new @storage_index = 0 @stack = Stack.new = end |
Instance Attribute Details
#argument_options ⇒ Object (readonly)
Returns the value of attribute argument_options.
134 135 136 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 134 def end |
#argument_size ⇒ Object
This is the list of information about the arguments to this instruction sequence.
133 134 135 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 133 def argument_size @argument_size end |
#catch_table ⇒ Object (readonly)
The catch table for this instruction sequence.
137 138 139 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 137 def catch_table @catch_table end |
#file ⇒ Object (readonly)
The source location of the instruction sequence.
123 124 125 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 123 def file @file end |
#inline_storages ⇒ Object (readonly)
The hash of names of instance and class variables pointing to the index of their associated inline storage.
147 148 149 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 147 def inline_storages @inline_storages end |
#insns ⇒ Object (readonly)
The list of instructions for this instruction sequence.
140 141 142 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 140 def insns @insns end |
#line ⇒ Object (readonly)
The source location of the instruction sequence.
123 124 125 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 123 def line @line end |
#local_table ⇒ Object (readonly)
The table of local variables.
143 144 145 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 143 def local_table @local_table end |
#name ⇒ Object (readonly)
The name of the instruction sequence.
120 121 122 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 120 def name @name end |
#options ⇒ Object (readonly)
These are various compilation options provided.
157 158 159 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 157 def end |
#parent_iseq ⇒ Object (readonly)
The parent instruction sequence, if there is one.
129 130 131 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 129 def parent_iseq @parent_iseq end |
#stack ⇒ Object (readonly)
An object that will track the current size of the stack and the maximum size of the stack for this instruction sequence.
154 155 156 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 154 def stack @stack end |
#storage_index ⇒ Object (readonly)
The index of the next inline storage that will be created.
150 151 152 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 150 def storage_index @storage_index end |
#type ⇒ Object (readonly)
The type of the instruction sequence.
126 127 128 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 126 def type @type end |
Class Method Details
.from(source, options = Compiler::Options.new, parent_iseq = nil) ⇒ Object
This method will create a new instruction sequence from a serialized RubyVM::InstructionSequence object.
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 965 def self.from(source, = Compiler::Options.new, parent_iseq = nil) iseq = new(source[5], source[6], source[8], source[9], parent_iseq, ) # 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..merge!(source[11]) if iseq.[:opt] iseq.[: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], , iseq), opnds[2]) when :defined iseq.defined(opnds[0], opnds[1], opnds[2]) when :definemethod iseq.definemethod(opnds[0], from(opnds[1], , iseq)) when :definesmethod iseq.definesmethod(opnds[0], from(opnds[1], , 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.(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], , 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], , 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_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], , 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], , 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], , 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], , 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 |
Instance Method Details
#adjuststack(number) ⇒ Object
611 612 613 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 611 def adjuststack(number) push(AdjustStack.new(number)) end |
#anytostring ⇒ Object
615 616 617 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 615 def anytostring push(AnyToString.new) end |
#block_child_iseq(line) ⇒ Object
431 432 433 434 435 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 431 def block_child_iseq(line) current = self current = current.parent_iseq while current.type == :block child_iseq("block in #{current.name}", line, :block) end |
#branchif(label) ⇒ Object
619 620 621 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 619 def branchif(label) push(BranchIf.new(label)) end |
#branchnil(label) ⇒ Object
623 624 625 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 623 def branchnil(label) push(BranchNil.new(label)) end |
#branchunless(label) ⇒ Object
627 628 629 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 627 def branchunless(label) push(BranchUnless.new(label)) end |
#catch_break(iseq, begin_label, end_label, exit_label, restore_sp) ⇒ Object
524 525 526 527 528 529 530 531 532 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 524 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 |
#catch_ensure(iseq, begin_label, end_label, exit_label, restore_sp) ⇒ Object
534 535 536 537 538 539 540 541 542 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 534 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 |
#catch_next(begin_label, end_label, exit_label, restore_sp) ⇒ Object
544 545 546 547 548 549 550 551 552 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 544 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 |
#catch_redo(begin_label, end_label, exit_label, restore_sp) ⇒ Object
554 555 556 557 558 559 560 561 562 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 554 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 |
#catch_rescue(iseq, begin_label, end_label, exit_label, restore_sp) ⇒ Object
564 565 566 567 568 569 570 571 572 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 564 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 |
#catch_retry(begin_label, end_label, exit_label, restore_sp) ⇒ Object
574 575 576 577 578 579 580 581 582 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 574 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 |
#checkkeyword(keyword_bits_index, keyword_index) ⇒ Object
631 632 633 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 631 def checkkeyword(keyword_bits_index, keyword_index) push(CheckKeyword.new(keyword_bits_index, keyword_index)) end |
#checkmatch(type) ⇒ Object
635 636 637 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 635 def checkmatch(type) push(CheckMatch.new(type)) end |
#checktype(type) ⇒ Object
639 640 641 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 639 def checktype(type) push(CheckType.new(type)) end |
#child_iseq(name, line, type) ⇒ Object
Child instruction sequence methods
427 428 429 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 427 def child_iseq(name, line, type) InstructionSequence.new(name, file, line, type, self, ) end |
#class_child_iseq(name, line) ⇒ Object
437 438 439 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 437 def class_child_iseq(name, line) child_iseq("<class:#{name}>", line, :class) end |
#compile! ⇒ Object
This method converts our linked list of instructions into a final array and performs any other compilation steps necessary.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 280 def compile! specialize_instructions! if .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 |
#concatarray ⇒ Object
643 644 645 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 643 def concatarray push(ConcatArray.new) end |
#concatstrings(number) ⇒ Object
647 648 649 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 647 def concatstrings(number) push(ConcatStrings.new(number)) end |
#defineclass(name, class_iseq, flags) ⇒ Object
655 656 657 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 655 def defineclass(name, class_iseq, flags) push(DefineClass.new(name, class_iseq, flags)) end |
#defined(type, name, message) ⇒ Object
651 652 653 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 651 def defined(type, name, ) push(Defined.new(type, name, )) end |
#definemethod(name, method_iseq) ⇒ Object
659 660 661 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 659 def definemethod(name, method_iseq) push(DefineMethod.new(name, method_iseq)) end |
#definesmethod(name, method_iseq) ⇒ Object
663 664 665 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 663 def definesmethod(name, method_iseq) push(DefineSMethod.new(name, method_iseq)) end |
#disasm ⇒ Object
272 273 274 275 276 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 272 def disasm disassembler = Disassembler.new disassembler.enqueue(self) disassembler.format! end |
#dup ⇒ Object
667 668 669 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 667 def dup push(Dup.new) end |
#duparray(object) ⇒ Object
671 672 673 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 671 def duparray(object) push(DupArray.new(object)) end |
#duphash(object) ⇒ Object
675 676 677 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 675 def duphash(object) push(DupHash.new(object)) end |
#dupn(number) ⇒ Object
679 680 681 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 679 def dupn(number) push(DupN.new(number)) end |
#eval ⇒ Object
223 224 225 226 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 223 def eval raise "Unsupported platform" if ISEQ_LOAD.nil? Fiddle.dlunwrap(ISEQ_LOAD.call(Fiddle.dlwrap(to_a), 0, nil)).eval end |
#event(name) ⇒ Object
607 608 609 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 607 def event(name) push(name) end |
#expandarray(length, flags) ⇒ Object
683 684 685 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 683 def (length, flags) push(ExpandArray.new(length, flags)) end |
#getblockparam(index, level) ⇒ Object
687 688 689 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 687 def getblockparam(index, level) push(GetBlockParam.new(index, level)) end |
#getblockparamproxy(index, level) ⇒ Object
691 692 693 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 691 def getblockparamproxy(index, level) push(GetBlockParamProxy.new(index, level)) end |
#getclassvariable(name) ⇒ Object
695 696 697 698 699 700 701 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 695 def getclassvariable(name) if RUBY_VERSION < "3.0" push(Legacy::GetClassVariable.new(name)) else push(GetClassVariable.new(name, inline_storage_for(name))) end end |
#getconstant(name) ⇒ Object
703 704 705 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 703 def getconstant(name) push(GetConstant.new(name)) end |
#getglobal(name) ⇒ Object
707 708 709 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 707 def getglobal(name) push(GetGlobal.new(name)) end |
#getinstancevariable(name) ⇒ Object
711 712 713 714 715 716 717 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 711 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 |
#getlocal(index, level) ⇒ Object
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 719 def getlocal(index, level) if .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 |
#getspecial(key, type) ⇒ Object
738 739 740 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 738 def getspecial(key, type) push(GetSpecial.new(key, type)) end |
#inline_storage ⇒ Object
198 199 200 201 202 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 198 def inline_storage storage = storage_index @storage_index += 1 storage end |
#inline_storage_for(name) ⇒ Object
204 205 206 207 208 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 204 def inline_storage_for(name) inline_storages[name] = inline_storage unless inline_storages.key?(name) inline_storages[name] end |
#intern ⇒ Object
742 743 744 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 742 def intern push(Intern.new) end |
#invokeblock(calldata) ⇒ Object
746 747 748 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 746 def invokeblock(calldata) push(InvokeBlock.new(calldata)) end |
#invokesuper(calldata, block_iseq) ⇒ Object
750 751 752 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 750 def invokesuper(calldata, block_iseq) push(InvokeSuper.new(calldata, block_iseq)) end |
#jump(label) ⇒ Object
754 755 756 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 754 def jump(label) push(Jump.new(label)) end |
#label ⇒ Object
Instruction push methods
588 589 590 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 588 def label Label.new end |
#leave ⇒ Object
758 759 760 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 758 def leave push(Leave.new) end |
#length ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 210 def length insns .each .inject(0) do |sum, insn| case insn when Integer, Label, Symbol sum else sum + insn.length end end end |
#local_variable(name, level = 0) ⇒ Object
Query methods
190 191 192 193 194 195 196 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 190 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 |
#method_child_iseq(name, line) ⇒ Object
441 442 443 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 441 def method_child_iseq(name, line) child_iseq(name, line, :method) end |
#module_child_iseq(name, line) ⇒ Object
445 446 447 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 445 def module_child_iseq(name, line) child_iseq("<module:#{name}>", line, :class) end |
#newarray(number) ⇒ Object
762 763 764 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 762 def newarray(number) push(NewArray.new(number)) end |
#newarraykwsplat(number) ⇒ Object
766 767 768 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 766 def newarraykwsplat(number) push(NewArrayKwSplat.new(number)) end |
#newhash(number) ⇒ Object
770 771 772 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 770 def newhash(number) push(NewHash.new(number)) end |
#newrange(exclude_end) ⇒ Object
774 775 776 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 774 def newrange(exclude_end) push(NewRange.new(exclude_end)) end |
#nop ⇒ Object
778 779 780 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 778 def nop push(Nop.new) end |
#objtostring(calldata) ⇒ Object
782 783 784 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 782 def objtostring(calldata) push(ObjToString.new(calldata)) end |
#once(iseq, cache) ⇒ Object
786 787 788 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 786 def once(iseq, cache) push(Once.new(iseq, cache)) end |
#opt_aref_with(object, calldata) ⇒ Object
790 791 792 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 790 def opt_aref_with(object, calldata) push(OptArefWith.new(object, calldata)) end |
#opt_aset_with(object, calldata) ⇒ Object
794 795 796 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 794 def opt_aset_with(object, calldata) push(OptAsetWith.new(object, calldata)) end |
#opt_case_dispatch(case_dispatch_hash, else_label) ⇒ Object
798 799 800 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 798 def opt_case_dispatch(case_dispatch_hash, else_label) push(OptCaseDispatch.new(case_dispatch_hash, else_label)) end |
#opt_getconstant_path(names) ⇒ Object
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 802 def opt_getconstant_path(names) if RUBY_VERSION < "3.2" || !.inline_const_cache? cache = nil cache_filled_label = nil if .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 .inline_const_cache? opt_setinlinecache(cache) push(cache_filled_label) end else push(OptGetConstantPath.new(names)) end end |
#opt_getinlinecache(label, cache) ⇒ Object
838 839 840 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 838 def opt_getinlinecache(label, cache) push(Legacy::OptGetInlineCache.new(label, cache)) end |
#opt_setinlinecache(cache) ⇒ Object
842 843 844 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 842 def opt_setinlinecache(cache) push(Legacy::OptSetInlineCache.new(cache)) end |
#pop ⇒ Object
846 847 848 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 846 def pop push(Pop.new) end |
#push(value) ⇒ Object
592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 592 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 |
#putnil ⇒ Object
850 851 852 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 850 def putnil push(PutNil.new) end |
#putobject(object) ⇒ Object
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 854 def putobject(object) if .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 |
#putself ⇒ Object
872 873 874 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 872 def putself push(PutSelf.new) end |
#putspecialobject(object) ⇒ Object
876 877 878 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 876 def putspecialobject(object) push(PutSpecialObject.new(object)) end |
#putstring(object) ⇒ Object
880 881 882 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 880 def putstring(object) push(PutString.new(object)) end |
#send(calldata, block_iseq = nil) ⇒ Object
884 885 886 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 884 def send(calldata, block_iseq = nil) push(Send.new(calldata, block_iseq)) end |
#setblockparam(index, level) ⇒ Object
888 889 890 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 888 def setblockparam(index, level) push(SetBlockParam.new(index, level)) end |
#setclassvariable(name) ⇒ Object
892 893 894 895 896 897 898 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 892 def setclassvariable(name) if RUBY_VERSION < "3.0" push(Legacy::SetClassVariable.new(name)) else push(SetClassVariable.new(name, inline_storage_for(name))) end end |
#setconstant(name) ⇒ Object
900 901 902 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 900 def setconstant(name) push(SetConstant.new(name)) end |
#setglobal(name) ⇒ Object
904 905 906 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 904 def setglobal(name) push(SetGlobal.new(name)) end |
#setinstancevariable(name) ⇒ Object
908 909 910 911 912 913 914 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 908 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 |
#setlocal(index, level) ⇒ Object
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 916 def setlocal(index, level) if .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 |
#setn(number) ⇒ Object
935 936 937 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 935 def setn(number) push(SetN.new(number)) end |
#setspecial(key) ⇒ Object
939 940 941 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 939 def setspecial(key) push(SetSpecial.new(key)) end |
#singleton_class_child_iseq(line) ⇒ Object
449 450 451 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 449 def singleton_class_child_iseq(line) child_iseq("singleton class", line, :class) end |
#specialize_instructions! ⇒ Object
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 316 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 :max node.value = OptNewArrayMax.new(value.number) node.next_node = next_node.next_node when :min node.value = OptNewArrayMin.new(value.number) 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 |
#splatarray(flag) ⇒ Object
943 944 945 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 943 def splatarray(flag) push(SplatArray.new(flag)) end |
#swap ⇒ Object
947 948 949 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 947 def swap push(Swap.new) end |
#throw(type) ⇒ Object
951 952 953 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 951 def throw(type) push(Throw.new(type)) end |
#to_a ⇒ Object
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 228 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 = .dup [:opt].map!(&:name) if [: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, , catch_table.map(&:to_a), dumped ] end |
#topn(number) ⇒ Object
955 956 957 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 955 def topn(number) push(TopN.new(number)) end |
#toregexp(options, length) ⇒ Object
959 960 961 |
# File 'lib/syntax_tree/yarv/instruction_sequence.rb', line 959 def toregexp(, length) push(ToRegExp.new(, length)) end |