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