--- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2017-09-12 22:24:39.144380068 -0700 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2017-09-12 22:24:38.993373264 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -374,6 +374,7 @@ import org.graalvm.compiler.nodes.extended.StateSplitProxyNode; import org.graalvm.compiler.nodes.extended.ValueAnchorNode; import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @@ -933,8 +934,13 @@ * @param type the unresolved type of the constant */ protected void handleUnresolvedLoadConstant(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + /* + * Track source position for deopt nodes even if + * GraphBuilderConfiguration.trackNodeSourcePosition is not set. + */ + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -942,7 +948,7 @@ * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { - assert !graphBuilderConfig.eagerResolving(); + assert !graphBuilderConfig.unresolvedIsError(); append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); } @@ -952,9 +958,10 @@ * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { - assert !graphBuilderConfig.eagerResolving(); + assert !graphBuilderConfig.unresolvedIsError(); AbstractBeginNode successor = graph.add(new BeginNode()); DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1)); lastInstr = successor; frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0)); @@ -964,8 +971,9 @@ * @param type the type being instantiated */ protected void handleUnresolvedNewInstance(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -973,8 +981,9 @@ * @param length the length of the array */ protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -982,8 +991,9 @@ * @param dims the dimensions for the multi-array */ protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -991,8 +1001,9 @@ * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -1001,16 +1012,18 @@ * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** * @param type */ protected void handleUnresolvedExceptionType(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -1018,8 +1031,9 @@ * @param invokeKind */ protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) { @@ -1307,7 +1321,12 @@ return false; } - protected void genInvokeStatic(JavaMethod target) { + protected void genInvokeStatic(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeStatic(target); + } + + void genInvokeStatic(JavaMethod target) { if (callTargetIsResolved(target)) { ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); @@ -1332,6 +1351,11 @@ } } + protected void genInvokeInterface(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeInterface(target); + } + protected void genInvokeInterface(JavaMethod target) { if (callTargetIsResolved(target)) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); @@ -1341,44 +1365,108 @@ } } - protected void genInvokeDynamic(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { - JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); - if (appendix != null) { - frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); - } - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false)); - appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); - } else { + protected void genInvokeDynamic(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeDynamic(target); + } + + void genInvokeDynamic(JavaMethod target) { + if (!(target instanceof ResolvedJavaMethod) || !genDynamicInvokeHelper((ResolvedJavaMethod) target, stream.readCPI4(), INVOKEDYNAMIC)) { handleUnresolvedInvoke(target, InvokeKind.Static); } } - protected void genInvokeVirtual(JavaMethod target) { - if (callTargetIsResolved(target)) { - /* - * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) - * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see - * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic - */ - boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic(); - JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL); - if (appendix != null) { - frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); - } - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); - if (hasReceiver) { - appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + protected void genInvokeVirtual(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeVirtual(target); + } + + private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) { + assert opcode == INVOKEDYNAMIC || opcode == INVOKEVIRTUAL; + + InvokeDynamicPlugin invokeDynamicPlugin = graphBuilderConfig.getPlugins().getInvokeDynamicPlugin(); + + if (opcode == INVOKEVIRTUAL && invokeDynamicPlugin != null && !invokeDynamicPlugin.isResolvedDynamicInvoke(this, cpi, opcode)) { + // regular invokevirtual, let caller handle it + return false; + } + + if (GeneratePIC.getValue(options) && (invokeDynamicPlugin == null || !invokeDynamicPlugin.supportsDynamicInvoke(this, cpi, opcode))) { + // bail out if static compiler and no dynamic type support + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + + JavaConstant appendix = constantPool.lookupAppendix(cpi, opcode); + ValueNode appendixNode = null; + + if (appendix != null) { + if (invokeDynamicPlugin != null) { + invokeDynamicPlugin.recordDynamicMethod(this, cpi, opcode, target); + + // Will perform runtime type checks and static initialization + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore); } else { - appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); + appendixNode = ConstantNode.forConstant(appendix, metaAccess, graph); } + + frameState.push(JavaKind.Object, appendixNode); + + } else if (GeneratePIC.getValue(options)) { + // Need to emit runtime guard and perform static initialization. + // Not implemented yet. + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + + boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic(); + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); + if (hasReceiver) { + appendInvoke(InvokeKind.Virtual, target, args); } else { + appendInvoke(InvokeKind.Static, target, args); + } + + return true; + } + + void genInvokeVirtual(JavaMethod target) { + if (!genInvokeVirtualHelper(target)) { handleUnresolvedInvoke(target, InvokeKind.Virtual); } + } + + private boolean genInvokeVirtualHelper(JavaMethod target) { + if (!callTargetIsResolved(target)) { + return false; + } + + ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; + int cpi = stream.readCPI(); + + /* + * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or + * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see + * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic + */ + + if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) { + return true; + } + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); + appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + + return true; + } + + protected void genInvokeSpecial(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeSpecial(target); } - protected void genInvokeSpecial(JavaMethod target) { + void genInvokeSpecial(JavaMethod target) { if (callTargetIsResolved(target)) { assert target != null; assert target.getSignature() != null; @@ -2149,9 +2237,9 @@ TTY.println(s); } - protected BytecodeParserError asParserError(Throwable e) { + protected RuntimeException throwParserError(Throwable e) { if (e instanceof BytecodeParserError) { - return (BytecodeParserError) e; + throw (BytecodeParserError) e; } BytecodeParser bp = this; BytecodeParserError res = new BytecodeParserError(e); @@ -2159,7 +2247,7 @@ res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci())); bp = bp.parent; } - return res; + throw res; } protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { @@ -2837,7 +2925,7 @@ // Don't wrap bailouts as parser errors throw e; } catch (Throwable e) { - throw asParserError(e); + throw throwParserError(e); } if (lastInstr == null || lastInstr.next() != null) { @@ -3257,7 +3345,7 @@ int nextBC = stream.readUByte(nextBCI); if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) { stream.next(); - genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value); + genGetField(stream.readCPI(), Bytecodes.GETFIELD, value); } else { frameState.push(JavaKind.Object, value); } @@ -3506,15 +3594,18 @@ return result; } - private JavaField lookupField(int cpi, int opcode) { + protected JavaField lookupField(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaField result = constantPool.lookupField(cpi, method, opcode); + if (graphBuilderConfig.eagerResolving()) { - assert result instanceof ResolvedJavaField : "Not resolved: " + result; - ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); - if (!declaringClass.isInitialized()) { - assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; - declaringClass.initialize(); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result; + if (result instanceof ResolvedJavaField) { + ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); + if (!declaringClass.isInitialized()) { + assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; + declaringClass.initialize(); + } } } assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; @@ -3524,11 +3615,11 @@ private Object lookupConstant(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); Object result = constantPool.lookupConstant(cpi); - assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; + assert !graphBuilderConfig.unresolvedIsError() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; return result; } - private void maybeEagerlyResolve(int cpi, int bytecode) { + protected void maybeEagerlyResolve(int cpi, int bytecode) { if (intrinsicContext != null) { constantPool.loadReferencedType(cpi, bytecode); } else if (graphBuilderConfig.eagerResolving()) { @@ -3653,9 +3744,12 @@ } } - void genNewInstance(int cpi) { + protected void genNewInstance(int cpi) { JavaType type = lookupType(cpi, NEW); + genNewInstance(type); + } + void genNewInstance(JavaType type) { if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { handleUnresolvedNewInstance(type); return; @@ -3790,8 +3884,13 @@ frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims))); } - private void genGetField(JavaField field) { - genGetField(field, frameState.pop(JavaKind.Object)); + protected void genGetField(int cpi, int opcode) { + genGetField(cpi, opcode, frameState.pop(JavaKind.Object)); + } + + protected void genGetField(int cpi, int opcode, ValueNode receiverInput) { + JavaField field = lookupField(cpi, opcode); + genGetField(field, receiverInput); } private void genGetField(JavaField field, ValueNode receiverInput) { @@ -3867,7 +3966,12 @@ return false; } - private void genPutField(JavaField field) { + protected void genPutField(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genPutField(field); + } + + protected void genPutField(JavaField field) { genPutField(field, frameState.pop(field.getJavaKind())); } @@ -3895,6 +3999,11 @@ } } + protected void genGetStatic(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genGetStatic(field); + } + private void genGetStatic(JavaField field) { ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null); if (resolvedField == null) { @@ -3956,7 +4065,12 @@ return null; } - private void genPutStatic(JavaField field) { + protected void genPutStatic(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genPutStatic(field); + } + + protected void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getJavaKind()); ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value); if (resolvedField == null) { @@ -4320,15 +4434,15 @@ case DRETURN : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break; case ARETURN : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break; case RETURN : genReturn(null, JavaKind.Void); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, opcode); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, opcode); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, opcode); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, opcode); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(cpi, opcode); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(cpi, opcode); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(cpi, opcode); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(cpi, opcode); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(cpi, opcode); break; case NEW : genNewInstance(stream.readCPI()); break; case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; case ANEWARRAY : genNewObjectArray(stream.readCPI()); break;