1 /* 2 * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.internal.classfile.impl; 26 27 import java.lang.classfile.*; 28 import java.lang.classfile.attribute.CodeAttribute; 29 import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; 30 import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; 31 import java.lang.classfile.attribute.StackMapTableAttribute; 32 import java.lang.classfile.attribute.UnknownAttribute; 33 import java.lang.classfile.constantpool.ClassEntry; 34 import java.lang.classfile.instruction.*; 35 import java.util.ArrayList; 36 import java.util.Collections; 37 import java.util.List; 38 import java.util.Objects; 39 import java.util.Optional; 40 import java.util.function.Consumer; 41 42 import static jdk.internal.classfile.impl.StackMapGenerator.*; 43 import static jdk.internal.classfile.impl.RawBytecodeHelper.*; 44 45 public final class CodeImpl 46 extends BoundAttribute.BoundCodeAttribute 47 implements LabelContext { 48 49 static final Instruction[] SINGLETON_INSTRUCTIONS = new Instruction[256]; 50 51 static { 52 for (var o : Opcode.values()) { 53 if (o.sizeIfFixed() == 1) { 54 SINGLETON_INSTRUCTIONS[o.bytecode()] = switch (o.kind()) { 55 case ARRAY_LOAD -> ArrayLoadInstruction.of(o); 56 case ARRAY_STORE -> ArrayStoreInstruction.of(o); 57 case CONSTANT -> ConstantInstruction.ofIntrinsic(o); 58 case CONVERT -> ConvertInstruction.of(o); 59 case LOAD -> new AbstractInstruction.UnboundLoadInstruction(o, BytecodeHelpers.intrinsicLoadSlot(o)); 60 case MONITOR -> MonitorInstruction.of(o); 61 case NOP -> NopInstruction.of(); 62 case OPERATOR -> OperatorInstruction.of(o); 63 case RETURN -> ReturnInstruction.of(o); 64 case STACK -> StackInstruction.of(o); 65 case STORE -> new AbstractInstruction.UnboundStoreInstruction(o, BytecodeHelpers.intrinsicStoreSlot(o)); 66 case THROW_EXCEPTION -> ThrowInstruction.of(); 67 default -> throw new AssertionError("invalid opcode: " + o); 68 }; 69 } 70 } 71 } 72 73 List<ExceptionCatch> exceptionTable; 74 List<Attribute<?>> attributes; 75 76 // Inflated for iteration 77 LabelImpl[] labels; 78 int[] lineNumbers; 79 boolean inflated; 80 81 public CodeImpl(AttributedElement enclosing, 82 ClassReader reader, 83 AttributeMapper<CodeAttribute> mapper, 84 int payloadStart) { 85 super(enclosing, reader, mapper, payloadStart); 86 } 87 88 // LabelContext 89 90 @Override 91 public Label newLabel() { 92 throw new UnsupportedOperationException("CodeAttribute only supports fixed labels"); 93 } 94 95 @Override 96 public void setLabelTarget(Label label, int bci) { 97 throw new UnsupportedOperationException("CodeAttribute only supports fixed labels"); 98 } 99 100 @Override 101 public Label getLabel(int bci) { 102 if (bci < 0 || bci > codeLength) 103 throw new IllegalArgumentException(String.format("Bytecode offset out of range; bci=%d, codeLength=%d", 104 bci, codeLength)); 105 if (labels == null) 106 labels = new LabelImpl[codeLength + 1]; 107 LabelImpl l = labels[bci]; 108 if (l == null) 109 l = labels[bci] = new LabelImpl(this, bci); 110 return l; 111 } 112 113 @Override 114 public int labelToBci(Label label) { 115 LabelImpl lab = (LabelImpl) label; 116 if (lab.labelContext() != this) 117 throw new IllegalArgumentException(String.format("Illegal label reuse; context=%s, label=%s", 118 this, lab.labelContext())); 119 return lab.getBCI(); 120 } 121 122 private void inflateMetadata() { 123 if (!inflated) { 124 if (labels == null) 125 labels = new LabelImpl[codeLength + 1]; 126 if (classReader.context().passLineNumbers()) 127 inflateLineNumbers(); 128 inflateJumpTargets(); 129 inflateTypeAnnotations(); 130 inflated = true; 131 } 132 } 133 134 // CodeAttribute 135 136 @Override 137 public List<Attribute<?>> attributes() { 138 if (attributes == null) { 139 attributes = BoundAttribute.readAttributes(this, classReader, attributePos, classReader.customAttributes()); 140 } 141 return attributes; 142 } 143 144 @Override 145 public void writeTo(BufWriterImpl buf) { 146 var methodInfo = (MethodInfo) enclosingMethod; 147 if (Util.canSkipMethodInflation(classReader, methodInfo, buf)) { 148 super.writeTo(buf); 149 } 150 else { 151 DirectCodeBuilder.build(methodInfo, 152 Util.writingAll(this), 153 (SplitConstantPool)buf.constantPool(), 154 buf.context(), 155 null).writeTo(buf); 156 } 157 } 158 159 // CodeModel 160 161 @Override 162 public Optional<MethodModel> parent() { 163 return Optional.of(enclosingMethod); 164 } 165 166 @Override 167 public void forEach(Consumer<? super CodeElement> consumer) { 168 Objects.requireNonNull(consumer); 169 inflateMetadata(); 170 boolean doLineNumbers = (lineNumbers != null); 171 generateCatchTargets(consumer); 172 if (classReader.context().passDebugElements()) 173 generateDebugElements(consumer); 174 generateUserAttributes(consumer); 175 for (int pos=codeStart; pos<codeEnd; ) { 176 if (labels[pos - codeStart] != null) 177 consumer.accept(labels[pos - codeStart]); 178 if (doLineNumbers && lineNumbers[pos - codeStart] != 0) 179 consumer.accept(LineNumberImpl.of(lineNumbers[pos - codeStart])); 180 int bc = classReader.readU1(pos); 181 Instruction instr = bcToInstruction(bc, pos); 182 consumer.accept(instr); 183 pos += instr.sizeInBytes(); 184 } 185 // There might be labels pointing to the bci at codeEnd 186 if (labels[codeEnd-codeStart] != null) 187 consumer.accept(labels[codeEnd - codeStart]); 188 if (doLineNumbers && lineNumbers[codeEnd - codeStart] != 0) 189 consumer.accept(LineNumberImpl.of(lineNumbers[codeEnd - codeStart])); 190 } 191 192 @Override 193 public List<ExceptionCatch> exceptionHandlers() { 194 if (exceptionTable == null) { 195 inflateMetadata(); 196 exceptionTable = new ArrayList<>(exceptionHandlerCnt); 197 iterateExceptionHandlers(new ExceptionHandlerAction() { 198 @Override 199 public void accept(int s, int e, int h, int c) { 200 ClassEntry catchTypeEntry = c == 0 201 ? null 202 : constantPool().entryByIndex(c, ClassEntry.class); 203 exceptionTable.add(new AbstractPseudoInstruction.ExceptionCatchImpl(getLabel(h), getLabel(s), getLabel(e), catchTypeEntry)); 204 } 205 }); 206 exceptionTable = Collections.unmodifiableList(exceptionTable); 207 } 208 return exceptionTable; 209 } 210 211 private void generateUserAttributes(Consumer<? super CodeElement> consumer) { 212 for (var attr : attributes) { 213 if (attr instanceof CustomAttribute || attr instanceof UnknownAttribute) { 214 consumer.accept((CodeElement) attr); 215 } 216 } 217 } 218 219 public boolean compareCodeBytes(BufWriterImpl buf, int offset, int len) { 220 return codeLength == len 221 && classReader.compare(buf, offset, codeStart, codeLength); 222 } 223 224 private int adjustForObjectOrUninitialized(int bci) { 225 int vt = classReader.readU1(bci); 226 //inflate newTarget labels from Uninitialized VTIs 227 if (vt == 8) inflateLabel(classReader.readU2(bci + 1)); 228 return (vt == 7 || vt == 8) ? bci + 3 : bci + 1; 229 } 230 231 private void inflateLabel(int bci) { 232 if (bci < 0 || bci > codeLength) 233 throw new IllegalArgumentException(String.format("Bytecode offset out of range; bci=%d, codeLength=%d", 234 bci, codeLength)); 235 if (labels[bci] == null) 236 labels[bci] = new LabelImpl(this, bci); 237 } 238 239 private void inflateLineNumbers() { 240 for (Attribute<?> a : attributes()) { 241 if (a.attributeMapper() == Attributes.lineNumberTable()) { 242 BoundLineNumberTableAttribute attr = (BoundLineNumberTableAttribute) a; 243 if (lineNumbers == null) 244 lineNumbers = new int[codeLength + 1]; 245 246 int nLn = classReader.readU2(attr.payloadStart); 247 int p = attr.payloadStart + 2; 248 int pEnd = p + (nLn * 4); 249 for (; p < pEnd; p += 4) { 250 int startPc = classReader.readU2(p); 251 if (startPc > codeLength) { 252 throw new IllegalArgumentException(String.format( 253 "Line number start_pc out of range; start_pc=%d, codeLength=%d", startPc, codeLength)); 254 } 255 int lineNumber = classReader.readU2(p + 2); 256 lineNumbers[startPc] = lineNumber; 257 } 258 } 259 } 260 } 261 262 private void inflateJumpTargets() { 263 Optional<StackMapTableAttribute> a = findAttribute(Attributes.stackMapTable()); 264 if (a.isEmpty()) { 265 if (classReader.readU2(6) <= ClassFile.JAVA_6_VERSION) { 266 //fallback to jump targets inflation without StackMapTableAttribute 267 for (int pos=codeStart; pos<codeEnd; ) { 268 var i = bcToInstruction(classReader.readU1(pos), pos); 269 switch (i.opcode().kind()) { 270 case BRANCH -> ((BranchInstruction) i).target(); 271 case DISCONTINUED_JSR -> ((DiscontinuedInstruction.JsrInstruction) i).target(); 272 case LOOKUP_SWITCH -> { 273 var ls = (LookupSwitchInstruction) i; 274 ls.defaultTarget(); 275 ls.cases(); 276 } 277 case TABLE_SWITCH -> { 278 var ts = (TableSwitchInstruction) i; 279 ts.defaultTarget(); 280 ts.cases(); 281 } 282 default -> {} 283 } 284 pos += i.sizeInBytes(); 285 } 286 } 287 return; 288 } 289 int stackMapPos = ((BoundAttribute<StackMapTableAttribute>) a.get()).payloadStart; 290 291 int bci = -1; //compensate for offsetDelta + 1 292 int nEntries = classReader.readU2(stackMapPos); 293 int p = stackMapPos + 2; 294 for (int i = 0; i < nEntries; ++i) { 295 int frameType = classReader.readU1(p); 296 int offsetDelta = -1; 297 if (frameType <= SAME_FRAME_END) { 298 offsetDelta = frameType; 299 ++p; 300 } 301 else if (frameType <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) { 302 offsetDelta = frameType & 0x3f; 303 p = adjustForObjectOrUninitialized(p + 1); 304 } 305 else { 306 switch (frameType) { 307 case EARLY_LARVAL -> { 308 int numberOfUnsetFields = classReader.readU2(p + 1); 309 p += 3; 310 p += 2 * numberOfUnsetFields; 311 i--; // one more enclosed frame 312 continue; 313 } 314 case SAME_LOCALS_1_STACK_ITEM_EXTENDED -> { 315 offsetDelta = classReader.readU2(p + 1); 316 p = adjustForObjectOrUninitialized(p + 3); 317 } 318 case CHOP_FRAME_START, CHOP_FRAME_START + 1, CHOP_FRAME_END, SAME_FRAME_EXTENDED -> { 319 offsetDelta = classReader.readU2(p + 1); 320 p += 3; 321 } 322 case APPEND_FRAME_START, APPEND_FRAME_START + 1, APPEND_FRAME_END -> { 323 offsetDelta = classReader.readU2(p + 1); 324 int k = frameType - APPEND_FRAME_START + 1; 325 p += 3; 326 for (int c = 0; c < k; ++c) { 327 p = adjustForObjectOrUninitialized(p); 328 } 329 } 330 case FULL_FRAME -> { 331 offsetDelta = classReader.readU2(p + 1); 332 p += 3; 333 int k = classReader.readU2(p); 334 p += 2; 335 for (int c = 0; c < k; ++c) { 336 p = adjustForObjectOrUninitialized(p); 337 } 338 k = classReader.readU2(p); 339 p += 2; 340 for (int c = 0; c < k; ++c) { 341 p = adjustForObjectOrUninitialized(p); 342 } 343 } 344 default -> throw new IllegalArgumentException("Bad frame type: " + frameType); 345 } 346 } 347 bci += offsetDelta + 1; 348 inflateLabel(bci); 349 } 350 } 351 352 private void inflateTypeAnnotations() { 353 findAttribute(Attributes.runtimeVisibleTypeAnnotations()).ifPresent(RuntimeVisibleTypeAnnotationsAttribute::annotations); 354 findAttribute(Attributes.runtimeInvisibleTypeAnnotations()).ifPresent(RuntimeInvisibleTypeAnnotationsAttribute::annotations); 355 } 356 357 private void generateCatchTargets(Consumer<? super CodeElement> consumer) { 358 // We attach all catch targets to bci zero, because trying to attach them 359 // to their range could subtly affect the order of exception processing 360 iterateExceptionHandlers(new ExceptionHandlerAction() { 361 @Override 362 public void accept(int s, int e, int h, int c) { 363 ClassEntry catchType = c == 0 364 ? null 365 : classReader.entryByIndex(c, ClassEntry.class); 366 consumer.accept(new AbstractPseudoInstruction.ExceptionCatchImpl(getLabel(h), getLabel(s), getLabel(e), catchType)); 367 } 368 }); 369 } 370 371 private void generateDebugElements(Consumer<? super CodeElement> consumer) { 372 for (Attribute<?> a : attributes()) { 373 if (a.attributeMapper() == Attributes.characterRangeTable()) { 374 var attr = (BoundCharacterRangeTableAttribute) a; 375 int cnt = classReader.readU2(attr.payloadStart); 376 int p = attr.payloadStart + 2; 377 int pEnd = p + (cnt * 14); 378 for (; p < pEnd; p += 14) { 379 var instruction = new BoundCharacterRange(this, p); 380 inflateLabel(instruction.startPc()); 381 inflateLabel(instruction.endPc() + 1); 382 consumer.accept(instruction); 383 } 384 } 385 else if (a.attributeMapper() == Attributes.localVariableTable()) { 386 var attr = (BoundLocalVariableTableAttribute) a; 387 int cnt = classReader.readU2(attr.payloadStart); 388 int p = attr.payloadStart + 2; 389 int pEnd = p + (cnt * 10); 390 for (; p < pEnd; p += 10) { 391 BoundLocalVariable instruction = new BoundLocalVariable(this, p); 392 inflateLabel(instruction.startPc()); 393 inflateLabel(instruction.startPc() + instruction.length()); 394 consumer.accept(instruction); 395 } 396 } 397 else if (a.attributeMapper() == Attributes.localVariableTypeTable()) { 398 var attr = (BoundLocalVariableTypeTableAttribute) a; 399 int cnt = classReader.readU2(attr.payloadStart); 400 int p = attr.payloadStart + 2; 401 int pEnd = p + (cnt * 10); 402 for (; p < pEnd; p += 10) { 403 BoundLocalVariableType instruction = new BoundLocalVariableType(this, p); 404 inflateLabel(instruction.startPc()); 405 inflateLabel(instruction.startPc() + instruction.length()); 406 consumer.accept(instruction); 407 } 408 } 409 else if (a.attributeMapper() == Attributes.runtimeVisibleTypeAnnotations()) { 410 consumer.accept((BoundRuntimeVisibleTypeAnnotationsAttribute) a); 411 } 412 else if (a.attributeMapper() == Attributes.runtimeInvisibleTypeAnnotations()) { 413 consumer.accept((BoundRuntimeInvisibleTypeAnnotationsAttribute) a); 414 } 415 } 416 } 417 418 public interface ExceptionHandlerAction { 419 void accept(int start, int end, int handler, int catchTypeIndex); 420 } 421 422 public void iterateExceptionHandlers(ExceptionHandlerAction a) { 423 int p = exceptionHandlerPos + 2; 424 for (int i = 0; i < exceptionHandlerCnt; ++i) { 425 a.accept(classReader.readU2(p), classReader.readU2(p + 2), classReader.readU2(p + 4), classReader.readU2(p + 6)); 426 p += 8; 427 } 428 } 429 430 private Instruction bcToInstruction(int bc, int pos) { 431 return switch (bc) { 432 case BIPUSH -> new AbstractInstruction.BoundArgumentConstantInstruction(Opcode.BIPUSH, CodeImpl.this, pos); 433 case SIPUSH -> new AbstractInstruction.BoundArgumentConstantInstruction(Opcode.SIPUSH, CodeImpl.this, pos); 434 case LDC -> new AbstractInstruction.BoundLoadConstantInstruction(Opcode.LDC, CodeImpl.this, pos); 435 case LDC_W -> new AbstractInstruction.BoundLoadConstantInstruction(Opcode.LDC_W, CodeImpl.this, pos); 436 case LDC2_W -> new AbstractInstruction.BoundLoadConstantInstruction(Opcode.LDC2_W, CodeImpl.this, pos); 437 case ILOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ILOAD, CodeImpl.this, pos); 438 case LLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.LLOAD, CodeImpl.this, pos); 439 case FLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.FLOAD, CodeImpl.this, pos); 440 case DLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.DLOAD, CodeImpl.this, pos); 441 case ALOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ALOAD, CodeImpl.this, pos); 442 case ISTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ISTORE, CodeImpl.this, pos); 443 case LSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.LSTORE, CodeImpl.this, pos); 444 case FSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.FSTORE, CodeImpl.this, pos); 445 case DSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.DSTORE, CodeImpl.this, pos); 446 case ASTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ASTORE, CodeImpl.this, pos); 447 case IINC -> new AbstractInstruction.BoundIncrementInstruction(Opcode.IINC, CodeImpl.this, pos); 448 case IFEQ -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFEQ, CodeImpl.this, pos); 449 case IFNE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFNE, CodeImpl.this, pos); 450 case IFLT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFLT, CodeImpl.this, pos); 451 case IFGE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFGE, CodeImpl.this, pos); 452 case IFGT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFGT, CodeImpl.this, pos); 453 case IFLE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFLE, CodeImpl.this, pos); 454 case IF_ICMPEQ -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPEQ, CodeImpl.this, pos); 455 case IF_ICMPNE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPNE, CodeImpl.this, pos); 456 case IF_ICMPLT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPLT, CodeImpl.this, pos); 457 case IF_ICMPGE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPGE, CodeImpl.this, pos); 458 case IF_ICMPGT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPGT, CodeImpl.this, pos); 459 case IF_ICMPLE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPLE, CodeImpl.this, pos); 460 case IF_ACMPEQ -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ACMPEQ, CodeImpl.this, pos); 461 case IF_ACMPNE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ACMPNE, CodeImpl.this, pos); 462 case GOTO -> new AbstractInstruction.BoundBranchInstruction(Opcode.GOTO, CodeImpl.this, pos); 463 case TABLESWITCH -> new AbstractInstruction.BoundTableSwitchInstruction(Opcode.TABLESWITCH, CodeImpl.this, pos); 464 case LOOKUPSWITCH -> new AbstractInstruction.BoundLookupSwitchInstruction(Opcode.LOOKUPSWITCH, CodeImpl.this, pos); 465 case GETSTATIC -> new AbstractInstruction.BoundFieldInstruction(Opcode.GETSTATIC, CodeImpl.this, pos); 466 case PUTSTATIC -> new AbstractInstruction.BoundFieldInstruction(Opcode.PUTSTATIC, CodeImpl.this, pos); 467 case GETFIELD -> new AbstractInstruction.BoundFieldInstruction(Opcode.GETFIELD, CodeImpl.this, pos); 468 case PUTFIELD -> new AbstractInstruction.BoundFieldInstruction(Opcode.PUTFIELD, CodeImpl.this, pos); 469 case INVOKEVIRTUAL -> new AbstractInstruction.BoundInvokeInstruction(Opcode.INVOKEVIRTUAL, CodeImpl.this, pos); 470 case INVOKESPECIAL -> new AbstractInstruction.BoundInvokeInstruction(Opcode.INVOKESPECIAL, CodeImpl.this, pos); 471 case INVOKESTATIC -> new AbstractInstruction.BoundInvokeInstruction(Opcode.INVOKESTATIC, CodeImpl.this, pos); 472 case INVOKEINTERFACE -> new AbstractInstruction.BoundInvokeInterfaceInstruction(Opcode.INVOKEINTERFACE, CodeImpl.this, pos); 473 case INVOKEDYNAMIC -> new AbstractInstruction.BoundInvokeDynamicInstruction(Opcode.INVOKEDYNAMIC, CodeImpl.this, pos); 474 case NEW -> new AbstractInstruction.BoundNewObjectInstruction(CodeImpl.this, pos); 475 case NEWARRAY -> new AbstractInstruction.BoundNewPrimitiveArrayInstruction(Opcode.NEWARRAY, CodeImpl.this, pos); 476 case ANEWARRAY -> new AbstractInstruction.BoundNewReferenceArrayInstruction(Opcode.ANEWARRAY, CodeImpl.this, pos); 477 case CHECKCAST -> new AbstractInstruction.BoundTypeCheckInstruction(Opcode.CHECKCAST, CodeImpl.this, pos); 478 case INSTANCEOF -> new AbstractInstruction.BoundTypeCheckInstruction(Opcode.INSTANCEOF, CodeImpl.this, pos); 479 480 case WIDE -> { 481 int bclow = classReader.readU1(pos + 1); 482 yield switch (bclow) { 483 case ILOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ILOAD_W, this, pos); 484 case LLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.LLOAD_W, this, pos); 485 case FLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.FLOAD_W, this, pos); 486 case DLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.DLOAD_W, this, pos); 487 case ALOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ALOAD_W, this, pos); 488 case ISTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ISTORE_W, this, pos); 489 case LSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.LSTORE_W, this, pos); 490 case FSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.FSTORE_W, this, pos); 491 case DSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.DSTORE_W, this, pos); 492 case ASTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ASTORE_W, this, pos); 493 case IINC -> new AbstractInstruction.BoundIncrementInstruction(Opcode.IINC_W, this, pos); 494 case RET -> new AbstractInstruction.BoundRetInstruction(Opcode.RET_W, this, pos); 495 default -> throw new IllegalArgumentException("unknown wide instruction: " + bclow); 496 }; 497 } 498 499 case MULTIANEWARRAY -> new AbstractInstruction.BoundNewMultidimensionalArrayInstruction(Opcode.MULTIANEWARRAY, CodeImpl.this, pos); 500 case IFNULL -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFNULL, CodeImpl.this, pos); 501 case IFNONNULL -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFNONNULL, CodeImpl.this, pos); 502 case GOTO_W -> new AbstractInstruction.BoundBranchInstruction(Opcode.GOTO_W, CodeImpl.this, pos); 503 504 case JSR -> new AbstractInstruction.BoundJsrInstruction(Opcode.JSR, CodeImpl.this, pos); 505 case RET -> new AbstractInstruction.BoundRetInstruction(Opcode.RET, this, pos); 506 case JSR_W -> new AbstractInstruction.BoundJsrInstruction(Opcode.JSR_W, CodeImpl.this, pos); 507 default -> { 508 Instruction instr = SINGLETON_INSTRUCTIONS[bc]; 509 if (instr == null) 510 throw new IllegalArgumentException("unknown instruction: " + bc); 511 yield instr; 512 } 513 }; 514 } 515 516 @Override 517 public String toString() { 518 return String.format("CodeModel[id=%d]", System.identityHashCode(this)); 519 } 520 }