1 /* 2 * Copyright (c) 2009, 2019, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.nodes; 26 27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; 28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; 29 30 import java.util.Map; 31 32 import org.graalvm.compiler.core.common.LIRKind; 33 import org.graalvm.compiler.core.common.type.AbstractObjectStamp; 34 import org.graalvm.compiler.core.common.type.FloatStamp; 35 import org.graalvm.compiler.core.common.type.IntegerStamp; 36 import org.graalvm.compiler.core.common.type.Stamp; 37 import org.graalvm.compiler.core.common.type.StampFactory; 38 import org.graalvm.compiler.debug.GraalError; 39 import org.graalvm.compiler.graph.Node; 40 import org.graalvm.compiler.graph.NodeClass; 41 import org.graalvm.compiler.graph.NodeMap; 42 import org.graalvm.compiler.graph.iterators.NodeIterable; 43 import org.graalvm.compiler.lir.ConstantValue; 44 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 45 import org.graalvm.compiler.nodeinfo.NodeInfo; 46 import org.graalvm.compiler.nodeinfo.Verbosity; 47 import org.graalvm.compiler.nodes.calc.FloatingNode; 48 import org.graalvm.compiler.nodes.cfg.Block; 49 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; 50 import org.graalvm.compiler.nodes.spi.LIRLowerable; 51 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 52 53 import jdk.vm.ci.code.CodeUtil; 54 import jdk.vm.ci.meta.Constant; 55 import jdk.vm.ci.meta.ConstantReflectionProvider; 56 import jdk.vm.ci.meta.JavaConstant; 57 import jdk.vm.ci.meta.JavaKind; 58 import jdk.vm.ci.meta.MetaAccessProvider; 59 import jdk.vm.ci.meta.PrimitiveConstant; 60 import jdk.vm.ci.meta.ResolvedJavaType; 61 62 /** 63 * The {@code ConstantNode} represents a {@link Constant constant}. 64 */ 65 @NodeInfo(nameTemplate = "C({p#rawvalue}) {p#stampKind}", cycles = CYCLES_0, size = SIZE_1) 66 public final class ConstantNode extends FloatingNode implements LIRLowerable, ArrayLengthProvider { 67 68 public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class); 69 70 protected final Constant value; 71 72 private final int stableDimension; 73 private final boolean isDefaultStable; 74 createPrimitive(JavaConstant value)75 private static ConstantNode createPrimitive(JavaConstant value) { 76 assert value.getJavaKind() != JavaKind.Object; 77 return new ConstantNode(value, StampFactory.forConstant(value)); 78 } 79 80 /** 81 * Constructs a new node representing the specified constant. 82 * 83 * @param value the constant 84 */ ConstantNode(Constant value, Stamp stamp)85 public ConstantNode(Constant value, Stamp stamp) { 86 this(value, stamp, 0, false); 87 } 88 ConstantNode(Constant value, Stamp stamp, int stableDimension, boolean isDefaultStable)89 private ConstantNode(Constant value, Stamp stamp, int stableDimension, boolean isDefaultStable) { 90 super(TYPE, stamp); 91 assert stamp != null && stamp.isCompatible(value) : stamp + " " + value; 92 this.value = value; 93 this.stableDimension = stableDimension; 94 if (stableDimension == 0) { 95 /* 96 * Ensure that isDefaultStable has a canonical value to avoid having two constant nodes 97 * that only differ in this field. The value of isDefaultStable is only used when we 98 * have a stable array dimension. 99 */ 100 this.isDefaultStable = false; 101 } else { 102 this.isDefaultStable = isDefaultStable; 103 } 104 } 105 ConstantNode(@njectedNodeParameter Stamp stamp, @InjectedNodeParameter ConstantReflectionProvider constantReflection, @ConstantNodeParameter ResolvedJavaType type)106 public ConstantNode(@InjectedNodeParameter Stamp stamp, @InjectedNodeParameter ConstantReflectionProvider constantReflection, @ConstantNodeParameter ResolvedJavaType type) { 107 this(constantReflection.asJavaClass(type), stamp); 108 } 109 110 /** 111 * @return the constant value represented by this node 112 */ getValue()113 public Constant getValue() { 114 return value; 115 } 116 117 /** 118 * @return the number of stable dimensions if this is a stable array, otherwise 0 119 */ getStableDimension()120 public int getStableDimension() { 121 return stableDimension; 122 } 123 124 /** 125 * @return true if this is a stable array and the default elements are considered stable 126 */ isDefaultStable()127 public boolean isDefaultStable() { 128 return isDefaultStable; 129 } 130 131 /** 132 * Gathers all the {@link ConstantNode}s that are inputs to the 133 * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. 134 */ getConstantNodes(StructuredGraph graph)135 public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) { 136 return graph.getNodes().filter(ConstantNode.class); 137 } 138 139 /** 140 * Replaces this node at its usages with another node. 141 */ replace(StructuredGraph graph, Node replacement)142 public void replace(StructuredGraph graph, Node replacement) { 143 assert graph == graph(); 144 replaceAtUsagesAndDelete(replacement); 145 } 146 147 @Override generate(NodeLIRBuilderTool gen)148 public void generate(NodeLIRBuilderTool gen) { 149 LIRGeneratorTool lirTool = gen.getLIRGeneratorTool(); 150 LIRKind kind = lirTool.getLIRKind(stamp(NodeView.DEFAULT)); 151 if (onlyUsedInVirtualState()) { 152 gen.setResult(this, new ConstantValue(kind, value)); 153 } else if (lirTool.canInlineConstant(value) || (lirTool.mayEmbedConstantLoad(value) && hasExactlyOneUsage() && onlyUsedInCurrentBlock())) { 154 gen.setResult(this, new ConstantValue(lirTool.toRegisterKind(kind), value)); 155 } else { 156 gen.setResult(this, gen.getLIRGeneratorTool().emitConstant(kind, value)); 157 } 158 } 159 160 /** 161 * Expecting false for loop invariant. 162 */ onlyUsedInCurrentBlock()163 private boolean onlyUsedInCurrentBlock() { 164 assert graph().getLastSchedule() != null; 165 NodeMap<Block> nodeBlockMap = graph().getLastSchedule().getNodeToBlockMap(); 166 Block currentBlock = nodeBlockMap.get(this); 167 for (Node usage : usages()) { 168 if (currentBlock != nodeBlockMap.get(usage)) { 169 return false; 170 } 171 } 172 return true; 173 } 174 onlyUsedInVirtualState()175 private boolean onlyUsedInVirtualState() { 176 for (Node n : this.usages()) { 177 if (n instanceof VirtualState) { 178 // Only virtual usage. 179 } else { 180 return false; 181 } 182 } 183 return true; 184 } 185 forConstant(JavaConstant constant, MetaAccessProvider metaAccess, StructuredGraph graph)186 public static ConstantNode forConstant(JavaConstant constant, MetaAccessProvider metaAccess, StructuredGraph graph) { 187 if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) { 188 return forInt(constant.asInt(), graph); 189 } 190 if (constant.getJavaKind() == JavaKind.Object) { 191 return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess))); 192 } else { 193 return unique(graph, createPrimitive(constant)); 194 } 195 } 196 forConstant(JavaConstant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess)197 public static ConstantNode forConstant(JavaConstant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) { 198 if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) { 199 return forInt(constant.asInt()); 200 } 201 if (constant.getJavaKind() == JavaKind.Object) { 202 return new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess), stableDimension, isDefaultStable); 203 } else { 204 assert stableDimension == 0; 205 return createPrimitive(constant); 206 } 207 } 208 forConstant(JavaConstant array, MetaAccessProvider metaAccess)209 public static ConstantNode forConstant(JavaConstant array, MetaAccessProvider metaAccess) { 210 return forConstant(array, 0, false, metaAccess); 211 } 212 forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph)213 public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) { 214 return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess))); 215 } 216 forConstant(Stamp stamp, Constant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess)217 public static ConstantNode forConstant(Stamp stamp, Constant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) { 218 return new ConstantNode(constant, stamp.constant(constant, metaAccess), stableDimension, isDefaultStable); 219 } 220 forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess)221 public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess) { 222 return new ConstantNode(constant, stamp.constant(constant, metaAccess)); 223 } 224 225 /** 226 * Returns a node for a Java primitive. 227 */ forPrimitive(JavaConstant constant, StructuredGraph graph)228 public static ConstantNode forPrimitive(JavaConstant constant, StructuredGraph graph) { 229 assert constant.getJavaKind() != JavaKind.Object; 230 return forConstant(constant, null, graph); 231 } 232 233 /** 234 * Returns a node for a Java primitive. 235 */ forPrimitive(JavaConstant constant)236 public static ConstantNode forPrimitive(JavaConstant constant) { 237 assert constant.getJavaKind() != JavaKind.Object; 238 return forConstant(constant, null); 239 } 240 241 /** 242 * Returns a node for a primitive of a given type. 243 */ forPrimitive(Stamp stamp, JavaConstant constant, StructuredGraph graph)244 public static ConstantNode forPrimitive(Stamp stamp, JavaConstant constant, StructuredGraph graph) { 245 if (stamp instanceof IntegerStamp) { 246 assert constant.getJavaKind().isNumericInteger() && stamp.getStackKind() == constant.getJavaKind().getStackKind(); 247 IntegerStamp istamp = (IntegerStamp) stamp; 248 return forIntegerBits(istamp.getBits(), constant, graph); 249 } else { 250 assert constant.getJavaKind().isNumericFloat() && stamp.getStackKind() == constant.getJavaKind(); 251 return forPrimitive(constant, graph); 252 } 253 } 254 255 /** 256 * Returns a node for a primitive of a given type. 257 */ forPrimitive(Stamp stamp, Constant constant)258 public static ConstantNode forPrimitive(Stamp stamp, Constant constant) { 259 if (stamp instanceof IntegerStamp) { 260 PrimitiveConstant primitive = (PrimitiveConstant) constant; 261 assert primitive.getJavaKind().isNumericInteger() && stamp.getStackKind() == primitive.getJavaKind().getStackKind(); 262 IntegerStamp istamp = (IntegerStamp) stamp; 263 return forIntegerBits(istamp.getBits(), primitive); 264 } else if (stamp instanceof FloatStamp) { 265 PrimitiveConstant primitive = (PrimitiveConstant) constant; 266 assert primitive.getJavaKind().isNumericFloat() && stamp.getStackKind() == primitive.getJavaKind(); 267 return forConstant(primitive, null); 268 } else { 269 assert !(stamp instanceof AbstractObjectStamp); 270 return new ConstantNode(constant, stamp.constant(constant, null)); 271 } 272 } 273 274 /** 275 * Returns a node for a double constant. 276 * 277 * @param d the double value for which to create the instruction 278 * @return a node for a double constant 279 */ forDouble(double d, StructuredGraph graph)280 public static ConstantNode forDouble(double d, StructuredGraph graph) { 281 return unique(graph, createPrimitive(JavaConstant.forDouble(d))); 282 } 283 284 /** 285 * Returns a node for a double constant. 286 * 287 * @param d the double value for which to create the instruction 288 * @return a node for a double constant 289 */ forDouble(double d)290 public static ConstantNode forDouble(double d) { 291 return createPrimitive(JavaConstant.forDouble(d)); 292 } 293 294 /** 295 * Returns a node for a float constant. 296 * 297 * @param f the float value for which to create the instruction 298 * @return a node for a float constant 299 */ forFloat(float f, StructuredGraph graph)300 public static ConstantNode forFloat(float f, StructuredGraph graph) { 301 return unique(graph, createPrimitive(JavaConstant.forFloat(f))); 302 } 303 304 /** 305 * Returns a node for a float constant. 306 * 307 * @param f the float value for which to create the instruction 308 * @return a node for a float constant 309 */ forFloat(float f)310 public static ConstantNode forFloat(float f) { 311 return createPrimitive(JavaConstant.forFloat(f)); 312 } 313 314 /** 315 * Returns a node for an long constant. 316 * 317 * @param i the long value for which to create the instruction 318 * @return a node for an long constant 319 */ forLong(long i, StructuredGraph graph)320 public static ConstantNode forLong(long i, StructuredGraph graph) { 321 return unique(graph, createPrimitive(JavaConstant.forLong(i))); 322 } 323 324 /** 325 * Returns a node for an long constant. 326 * 327 * @param i the long value for which to create the instruction 328 * @return a node for an long constant 329 */ forLong(long i)330 public static ConstantNode forLong(long i) { 331 return createPrimitive(JavaConstant.forLong(i)); 332 } 333 334 /** 335 * Returns a node for an integer constant. 336 * 337 * @param i the integer value for which to create the instruction 338 * @return a node for an integer constant 339 */ forInt(int i, StructuredGraph graph)340 public static ConstantNode forInt(int i, StructuredGraph graph) { 341 return unique(graph, createPrimitive(JavaConstant.forInt(i))); 342 } 343 344 /** 345 * Returns a node for an integer constant. 346 * 347 * @param i the integer value for which to create the instruction 348 * @return a node for an integer constant 349 */ forInt(int i)350 public static ConstantNode forInt(int i) { 351 return createPrimitive(JavaConstant.forInt(i)); 352 } 353 354 /** 355 * Returns a node for a boolean constant. 356 * 357 * @param i the boolean value for which to create the instruction 358 * @return a node representing the boolean 359 */ forBoolean(boolean i, StructuredGraph graph)360 public static ConstantNode forBoolean(boolean i, StructuredGraph graph) { 361 return unique(graph, createPrimitive(JavaConstant.forInt(i ? 1 : 0))); 362 } 363 364 /** 365 * Returns a node for a boolean constant. 366 * 367 * @param i the boolean value for which to create the instruction 368 * @return a node representing the boolean 369 */ forBoolean(boolean i)370 public static ConstantNode forBoolean(boolean i) { 371 return createPrimitive(JavaConstant.forInt(i ? 1 : 0)); 372 } 373 374 /** 375 * Returns a node for a byte constant. 376 * 377 * @param i the byte value for which to create the instruction 378 * @return a node representing the byte 379 */ forByte(byte i, StructuredGraph graph)380 public static ConstantNode forByte(byte i, StructuredGraph graph) { 381 return unique(graph, createPrimitive(JavaConstant.forInt(i))); 382 } 383 384 /** 385 * Returns a node for a char constant. 386 * 387 * @param i the char value for which to create the instruction 388 * @return a node representing the char 389 */ forChar(char i, StructuredGraph graph)390 public static ConstantNode forChar(char i, StructuredGraph graph) { 391 return unique(graph, createPrimitive(JavaConstant.forInt(i))); 392 } 393 394 /** 395 * Returns a node for a short constant. 396 * 397 * @param i the short value for which to create the instruction 398 * @return a node representing the short 399 */ forShort(short i, StructuredGraph graph)400 public static ConstantNode forShort(short i, StructuredGraph graph) { 401 return unique(graph, createPrimitive(JavaConstant.forInt(i))); 402 } 403 unique(StructuredGraph graph, ConstantNode node)404 private static ConstantNode unique(StructuredGraph graph, ConstantNode node) { 405 return graph.unique(node); 406 } 407 forIntegerBits(int bits, JavaConstant constant, StructuredGraph graph)408 private static ConstantNode forIntegerBits(int bits, JavaConstant constant, StructuredGraph graph) { 409 long value = constant.asLong(); 410 long bounds = CodeUtil.signExtend(value, bits); 411 return unique(graph, new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds))); 412 } 413 414 /** 415 * Returns a node for a constant integer that's not directly representable as Java primitive 416 * (e.g. short). 417 */ forIntegerBits(int bits, long value, StructuredGraph graph)418 public static ConstantNode forIntegerBits(int bits, long value, StructuredGraph graph) { 419 return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value), graph); 420 } 421 forIntegerBits(int bits, JavaConstant constant)422 private static ConstantNode forIntegerBits(int bits, JavaConstant constant) { 423 long value = constant.asLong(); 424 long bounds = CodeUtil.signExtend(value, bits); 425 return new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds)); 426 } 427 428 /** 429 * Returns a node for a constant integer that's not directly representable as Java primitive 430 * (e.g. short). 431 */ forIntegerBits(int bits, long value)432 public static ConstantNode forIntegerBits(int bits, long value) { 433 return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value)); 434 } 435 436 /** 437 * Returns a node for a constant integer that's compatible to a given stamp. 438 */ forIntegerStamp(Stamp stamp, long value, StructuredGraph graph)439 public static ConstantNode forIntegerStamp(Stamp stamp, long value, StructuredGraph graph) { 440 if (stamp instanceof IntegerStamp) { 441 IntegerStamp intStamp = (IntegerStamp) stamp; 442 return forIntegerBits(intStamp.getBits(), value, graph); 443 } else { 444 return forIntegerKind(stamp.getStackKind(), value, graph); 445 } 446 } 447 448 /** 449 * Returns a node for a constant integer that's compatible to a given stamp. 450 */ forIntegerStamp(Stamp stamp, long value)451 public static ConstantNode forIntegerStamp(Stamp stamp, long value) { 452 if (stamp instanceof IntegerStamp) { 453 IntegerStamp intStamp = (IntegerStamp) stamp; 454 return forIntegerBits(intStamp.getBits(), value); 455 } else { 456 return forIntegerKind(stamp.getStackKind(), value); 457 } 458 } 459 forIntegerKind(JavaKind kind, long value, StructuredGraph graph)460 public static ConstantNode forIntegerKind(JavaKind kind, long value, StructuredGraph graph) { 461 switch (kind) { 462 case Byte: 463 case Short: 464 case Int: 465 return ConstantNode.forInt((int) value, graph); 466 case Long: 467 return ConstantNode.forLong(value, graph); 468 default: 469 throw GraalError.shouldNotReachHere("unknown kind " + kind); 470 } 471 } 472 forIntegerKind(JavaKind kind, long value)473 public static ConstantNode forIntegerKind(JavaKind kind, long value) { 474 switch (kind) { 475 case Byte: 476 case Short: 477 case Int: 478 return createPrimitive(JavaConstant.forInt((int) value)); 479 case Long: 480 return createPrimitive(JavaConstant.forLong(value)); 481 default: 482 throw GraalError.shouldNotReachHere("unknown kind " + kind); 483 } 484 } 485 forFloatingKind(JavaKind kind, double value, StructuredGraph graph)486 public static ConstantNode forFloatingKind(JavaKind kind, double value, StructuredGraph graph) { 487 switch (kind) { 488 case Float: 489 return ConstantNode.forFloat((float) value, graph); 490 case Double: 491 return ConstantNode.forDouble(value, graph); 492 default: 493 throw GraalError.shouldNotReachHere("unknown kind " + kind); 494 } 495 } 496 forFloatingKind(JavaKind kind, double value)497 public static ConstantNode forFloatingKind(JavaKind kind, double value) { 498 switch (kind) { 499 case Float: 500 return ConstantNode.forFloat((float) value); 501 case Double: 502 return ConstantNode.forDouble(value); 503 default: 504 throw GraalError.shouldNotReachHere("unknown kind " + kind); 505 } 506 } 507 508 /** 509 * Returns a node for a constant double that's compatible to a given stamp. 510 */ forFloatingStamp(Stamp stamp, double value, StructuredGraph graph)511 public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) { 512 return forFloatingKind(stamp.getStackKind(), value, graph); 513 } 514 515 /** 516 * Returns a node for a constant double that's compatible to a given stamp. 517 */ forFloatingStamp(Stamp stamp, double value)518 public static ConstantNode forFloatingStamp(Stamp stamp, double value) { 519 return forFloatingKind(stamp.getStackKind(), value); 520 } 521 defaultForKind(JavaKind kind, StructuredGraph graph)522 public static ConstantNode defaultForKind(JavaKind kind, StructuredGraph graph) { 523 return unique(graph, defaultForKind(kind)); 524 } 525 defaultForKind(JavaKind kind)526 public static ConstantNode defaultForKind(JavaKind kind) { 527 switch (kind) { 528 case Boolean: 529 case Byte: 530 case Char: 531 case Short: 532 case Int: 533 return ConstantNode.forInt(0); 534 case Double: 535 return ConstantNode.forDouble(0.0); 536 case Float: 537 return ConstantNode.forFloat(0.0f); 538 case Long: 539 return ConstantNode.forLong(0L); 540 case Object: 541 return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null); 542 default: 543 return null; 544 } 545 } 546 547 @Override getDebugProperties(Map<Object, Object> map)548 public Map<Object, Object> getDebugProperties(Map<Object, Object> map) { 549 Map<Object, Object> properties = super.getDebugProperties(map); 550 properties.put("rawvalue", value.toValueString()); 551 properties.put("stampKind", stamp.unrestricted().toString()); 552 return properties; 553 } 554 555 @Override toString(Verbosity verbosity)556 public String toString(Verbosity verbosity) { 557 if (verbosity == Verbosity.Name) { 558 return super.toString(Verbosity.Name) + "(" + value.toValueString() + ", " + stamp(NodeView.DEFAULT).unrestricted().toString() + ")"; 559 } else { 560 return super.toString(verbosity); 561 } 562 } 563 564 @Override findLength(FindLengthMode mode, ConstantReflectionProvider constantReflection)565 public ValueNode findLength(FindLengthMode mode, ConstantReflectionProvider constantReflection) { 566 if (constantReflection == null || !(value instanceof JavaConstant) || ((JavaConstant) value).isNull()) { 567 return null; 568 } 569 Integer length = constantReflection.readArrayLength((JavaConstant) value); 570 if (length == null) { 571 return null; 572 } 573 return ConstantNode.forInt(length); 574 } 575 576 @NodeIntrinsic forClass(@onstantNodeParameter ResolvedJavaType type)577 public static native Class<?> forClass(@ConstantNodeParameter ResolvedJavaType type); 578 } 579