This commit is contained in:
Igor Veresov 2017-06-13 16:29:42 +00:00
commit 1cbd0bd202
84 changed files with 2799 additions and 362 deletions

View File

@ -61,6 +61,27 @@ suite = {
},
"projects" : {
# -------------- SDK --------------
"org.graalvm.options" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [],
"uses" : [],
"exports" : [
"<package-info>", # exports all packages containing package-info.java
],
"checkstyle" : "org.graalvm.api.word",
"javaCompliance" : "1.8",
"workingSets" : "API,SDK",
},
"org.graalvm.api.word" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [],
"checkstyle" : "org.graalvm.api.word",
"javaCompliance" : "1.8",
"workingSets" : "API,SDK",
},
# ------------- Graal -------------
@ -84,7 +105,7 @@ suite = {
"org.graalvm.compiler.options" : {
"subDir" : "share/classes",
"dependencies" : ["JVMCI_SERVICES", "JVMCI_API"],
"dependencies" : ["JVMCI_SERVICES", "JVMCI_API", "org.graalvm.util"],
"sourceDirs" : ["src"],
"dependencies" : ["org.graalvm.util"],
"checkstyle" : "org.graalvm.compiler.graph",
@ -594,15 +615,6 @@ suite = {
"workingSets" : "Graal,LIR,SPARC",
},
"org.graalvm.api.word" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"workingSets" : "API",
},
"org.graalvm.compiler.word" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -4,7 +4,9 @@
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Red Hat Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.aarch64;
import jdk.vm.ci.aarch64.AArch64Kind;
import jdk.vm.ci.meta.JavaConstant;
import org.graalvm.compiler.asm.aarch64.AArch64Address;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase;
public class AArch64AddressLoweringByUse extends AddressLoweringByUsePhase.AddressLoweringByUse {
private AArch64LIRKindTool kindtool;
public AArch64AddressLoweringByUse(AArch64LIRKindTool kindtool) {
this.kindtool = kindtool;
}
@Override
public AddressNode lower(ValueNode use, Stamp stamp, AddressNode address) {
if (address instanceof RawAddressNode) {
return doLower(stamp, address.getBase(), null);
} else if (address instanceof OffsetAddressNode) {
OffsetAddressNode offsetAddress = (OffsetAddressNode) address;
return doLower(stamp, offsetAddress.getBase(), offsetAddress.getOffset());
} else {
// must be an already transformed AArch64AddressNode
return address;
}
}
@Override
public AddressNode lower(AddressNode address) {
return lower(null, null, address);
}
private AddressNode doLower(Stamp stamp, ValueNode base, ValueNode index) {
AArch64AddressNode ret = new AArch64AddressNode(base, index);
AArch64Kind aarch64Kind = (stamp == null ? null : getAArch64Kind(stamp));
// improve the address as much as possible
boolean changed;
do {
changed = improve(aarch64Kind, ret);
} while (changed);
// avoid duplicates
return base.graph().unique(ret);
}
protected boolean improve(AArch64Kind kind, AArch64AddressNode ret) {
AArch64Address.AddressingMode mode = ret.getAddressingMode();
// if we have already set a displacement or set to base only mode then we are done
if (isDisplacementMode(mode) || isBaseOnlyMode(mode)) {
return false;
}
ValueNode base = ret.getBase();
ValueNode index = ret.getIndex();
// avoid a constant or null base if possible
if (base == null) {
ret.setBase(index);
ret.setIndex(base);
return true;
}
// make sure any integral JavaConstant
// is the index rather than the base
// strictly we don't need the conditions on index
// as we ought not to see two JavaConstant values
if (base.isJavaConstant() && base.asJavaConstant().getJavaKind().isNumericInteger() &&
index != null && !index.isJavaConstant()) {
ret.setBase(index);
ret.setIndex(base);
return true;
}
// if the base is an add then move it up
if (index == null && base instanceof AddNode) {
AddNode add = (AddNode) base;
ret.setBase(add.getX());
ret.setIndex(add.getY());
return true;
}
// we can try to fold a JavaConstant index into a displacement
if (index != null && index.isJavaConstant()) {
JavaConstant javaConstant = index.asJavaConstant();
if (javaConstant.getJavaKind().isNumericInteger()) {
long disp = javaConstant.asLong();
mode = immediateMode(kind, disp);
if (isDisplacementMode(mode)) {
index = null;
// we can fold this in as a displacement
// but first see if we can pull up any additional
// constants added into the base
boolean tryNextBase = (base instanceof AddNode);
while (tryNextBase) {
AddNode add = (AddNode) base;
tryNextBase = false;
ValueNode child = add.getX();
if (child.isJavaConstant() && child.asJavaConstant().getJavaKind().isNumericInteger()) {
long newDisp = disp + child.asJavaConstant().asLong();
AArch64Address.AddressingMode newMode = immediateMode(kind, newDisp);
if (newMode != AArch64Address.AddressingMode.REGISTER_OFFSET) {
disp = newDisp;
mode = newMode;
base = add.getY();
ret.setBase(base);
tryNextBase = (base instanceof AddNode);
}
} else {
child = add.getY();
if (child.isJavaConstant() && child.asJavaConstant().getJavaKind().isNumericInteger()) {
long newDisp = disp + child.asJavaConstant().asLong();
AArch64Address.AddressingMode newMode = immediateMode(kind, newDisp);
if (newMode != AArch64Address.AddressingMode.REGISTER_OFFSET) {
disp = newDisp;
mode = newMode;
base = add.getX();
ret.setBase(base);
tryNextBase = (base instanceof AddNode);
}
}
}
}
if (disp != 0) {
// ok now set the displacement in place of an index
ret.setIndex(null);
int scaleFactor = computeScaleFactor(kind, mode);
ret.setDisplacement(disp, scaleFactor, mode);
} else {
// reset to base register only
ret.setIndex(null);
ret.setDisplacement(0, 1, AArch64Address.AddressingMode.BASE_REGISTER_ONLY);
}
return true;
}
}
}
// nope cannot improve this any more
return false;
}
private AArch64Kind getAArch64Kind(Stamp stamp) {
LIRKind lirKind = stamp.getLIRKind(kindtool);
if (!lirKind.isValue()) {
if (!lirKind.isReference(0) || lirKind.getReferenceCount() != 1) {
return null;
}
}
return (AArch64Kind) lirKind.getPlatformKind();
}
private static AArch64Address.AddressingMode immediateMode(AArch64Kind kind, long value) {
if (kind != null) {
int size = kind.getSizeInBytes();
// this next test should never really fail
if ((value & (size - 1)) == 0) {
long encodedValue = value / size;
// assert value % size == 0
// we can try for a 12 bit scaled offset
if (NumUtil.isUnsignedNbit(12, encodedValue)) {
return AArch64Address.AddressingMode.IMMEDIATE_SCALED;
}
}
}
// we can try for a 9 bit unscaled offset
if (NumUtil.isSignedNbit(9, value)) {
return AArch64Address.AddressingMode.IMMEDIATE_UNSCALED;
}
// nope this index needs to be passed via offset register
return AArch64Address.AddressingMode.REGISTER_OFFSET;
}
private static int computeScaleFactor(AArch64Kind kind, AArch64Address.AddressingMode mode) {
if (mode == AArch64Address.AddressingMode.IMMEDIATE_SCALED) {
return kind.getSizeInBytes();
}
return 1;
}
boolean isBaseOnlyMode(AArch64Address.AddressingMode addressingMode) {
return addressingMode == AArch64Address.AddressingMode.BASE_REGISTER_ONLY;
}
private static boolean isDisplacementMode(AArch64Address.AddressingMode addressingMode) {
switch (addressingMode) {
case IMMEDIATE_POST_INDEXED:
case IMMEDIATE_PRE_INDEXED:
case IMMEDIATE_SCALED:
case IMMEDIATE_UNSCALED:
return true;
}
return false;
}
}

View File

@ -26,7 +26,6 @@ package org.graalvm.compiler.core.aarch64;
import org.graalvm.compiler.asm.aarch64.AArch64Address;
import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
@ -40,7 +39,7 @@ import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.Value;
/**
* Represents an address of the form... TODO.
* Represents an AArch64 address in the graph.
*/
@NodeInfo
public class AArch64AddressNode extends AddressNode implements LIRLowerable {
@ -52,7 +51,8 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
@OptionalInput private ValueNode index;
private AArch64Address.AddressingMode addressingMode;
private int displacement;
private long displacement;
private int scaleFactor;
public AArch64AddressNode(ValueNode base) {
this(base, null);
@ -63,6 +63,8 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
this.base = base;
this.index = index;
this.addressingMode = AddressingMode.REGISTER_OFFSET;
this.displacement = 0;
this.scaleFactor = 1;
}
@Override
@ -76,7 +78,6 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
AllocatableValue indexReference;
if (addressingMode.equals(AddressingMode.IMMEDIATE_UNSCALED)) {
indexReference = LIRKind.derivedBaseFromValue(indexValue);
throw GraalError.unimplemented();
} else {
if (LIRKind.isValue(indexValue.getValueKind())) {
indexReference = null;
@ -86,8 +87,7 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
}
LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference);
final boolean scaled = false;
gen.setResult(this, new AArch64AddressValue(kind, baseValue, indexValue, displacement, scaled, addressingMode));
gen.setResult(this, new AArch64AddressValue(kind, baseValue, indexValue, (int) displacement, scaleFactor, addressingMode));
}
@Override
@ -116,16 +116,22 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
this.index = index;
}
public int getDisplacement() {
public long getDisplacement() {
return displacement;
}
public void setDisplacement(int displacement) {
public void setDisplacement(long displacement, int scaleFactor, AArch64Address.AddressingMode addressingMode) {
this.displacement = displacement;
this.scaleFactor = scaleFactor;
this.addressingMode = addressingMode;
}
@Override
public long getMaxConstantDisplacement() {
return Long.MAX_VALUE;
return displacement;
}
public AddressingMode getAddressingMode() {
return addressingMode;
}
}

View File

@ -120,7 +120,7 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
if (address instanceof AArch64AddressValue) {
return (AArch64AddressValue) address;
} else {
return new AArch64AddressValue(address.getValueKind(), asAllocatable(address), Value.ILLEGAL, 0, false, AddressingMode.BASE_REGISTER_ONLY);
return new AArch64AddressValue(address.getValueKind(), asAllocatable(address), Value.ILLEGAL, 0, 1, AddressingMode.BASE_REGISTER_ONLY);
}
}

View File

@ -22,13 +22,13 @@
*/
package org.graalvm.compiler.core.aarch64;
import org.graalvm.compiler.java.DefaultSuitesProvider;
import org.graalvm.compiler.java.DefaultSuitesCreator;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
public class AArch64SuitesProvider extends DefaultSuitesProvider {
public class AArch64SuitesCreator extends DefaultSuitesCreator {
public AArch64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) {
super(compilerConfiguration, plugins);
}

View File

@ -22,16 +22,16 @@
*/
package org.graalvm.compiler.core.amd64;
import org.graalvm.compiler.java.DefaultSuitesProvider;
import org.graalvm.compiler.java.DefaultSuitesCreator;
import org.graalvm.compiler.lir.amd64.phases.StackMoveOptimizationPhase;
import org.graalvm.compiler.lir.phases.LIRSuites;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
public class AMD64SuitesProvider extends DefaultSuitesProvider {
public class AMD64SuitesCreator extends DefaultSuitesCreator {
public AMD64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
public AMD64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) {
super(compilerConfiguration, plugins);
}

View File

@ -24,7 +24,7 @@ package org.graalvm.compiler.core.sparc;
import java.util.ListIterator;
import org.graalvm.compiler.java.DefaultSuitesProvider;
import org.graalvm.compiler.java.DefaultSuitesCreator;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
@ -34,8 +34,9 @@ import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
import org.graalvm.compiler.phases.tiers.LowTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
public class SPARCSuitesProvider extends DefaultSuitesProvider {
public SPARCSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
public class SPARCSuitesCreator extends DefaultSuitesCreator {
public SPARCSuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) {
super(compilerConfiguration, plugins);
}

View File

@ -310,7 +310,7 @@ public class GraalCompiler {
LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule);
new LIRGenerationPhase().apply(backend.getTarget(), lirGenRes, context);
try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
try (Scope s = Debug.scope("LIRStages", nodeLirGen, lirGenRes, lir)) {
// Dump LIR along with HIR (the LIR is looked up from context)
Debug.dump(Debug.BASIC_LEVEL, graph.getLastSchedule(), "After LIR generation");
LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig, allocationRestrictedTo));

View File

@ -27,8 +27,9 @@ import static jdk.vm.ci.common.InitTimer.timer;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.aarch64.AArch64AddressLowering;
import org.graalvm.compiler.core.aarch64.AArch64SuitesProvider;
import org.graalvm.compiler.core.aarch64.AArch64AddressLoweringByUse;
import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
import org.graalvm.compiler.core.aarch64.AArch64SuitesCreator;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
@ -176,7 +177,7 @@ public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory {
}
protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins) {
return new HotSpotSuitesProvider(new AArch64SuitesProvider(compilerConfiguration, plugins), config, runtime, new AArch64AddressLowering());
return new AArch64HotSpotSuitesProvider(new AArch64SuitesCreator(compilerConfiguration, plugins), config, runtime, new AArch64AddressLoweringByUse(new AArch64LIRKindTool()));
}
protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {

View File

@ -36,7 +36,6 @@ import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator;
import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
@ -321,8 +320,7 @@ public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements H
LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes();
final int scaledDisplacement = offset >> NumUtil.log2Ceil(transferSize);
AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, scaledDisplacement, true, AddressingMode.IMMEDIATE_SCALED);
AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, offset, transferSize, AddressingMode.IMMEDIATE_SCALED);
append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null));
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Red Hat Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.aarch64;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase;
import org.graalvm.compiler.phases.common.ExpandLogicPhase;
import org.graalvm.compiler.phases.common.FixReadsPhase;
import org.graalvm.compiler.phases.tiers.LowTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
import org.graalvm.compiler.phases.tiers.SuitesCreator;
import java.util.ListIterator;
/**
* Subclass to factor out management of address lowering.
*/
public class AArch64HotSpotSuitesProvider extends HotSpotSuitesProvider {
private final AddressLoweringByUsePhase.AddressLoweringByUse addressLoweringByUse;
public AArch64HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime,
AddressLoweringByUsePhase.AddressLoweringByUse addressLoweringByUse) {
super(defaultSuitesCreator, config, runtime);
this.addressLoweringByUse = addressLoweringByUse;
}
@Override
public Suites createSuites(OptionValues options) {
Suites suites = super.createSuites(options);
ListIterator<BasePhase<? super LowTierContext>> findPhase = suites.getLowTier().findPhase(FixReadsPhase.class);
if (findPhase == null) {
findPhase = suites.getLowTier().findPhase(ExpandLogicPhase.class);
}
findPhase.add(new AddressLoweringByUsePhase(addressLoweringByUse));
return suites;
}
}

View File

@ -35,6 +35,7 @@ import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
@ -182,7 +183,7 @@ public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory {
*/
protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins,
HotSpotRegistersProvider registers, Replacements replacements, OptionValues options) {
return new HotSpotSuitesProvider(new AMD64HotSpotSuitesProvider(compilerConfiguration, plugins), config, runtime,
return new AddressLoweringHotSpotSuitesProvider(new AMD64HotSpotSuitesCreator(compilerConfiguration, plugins), config, runtime,
new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister(), options));
}

View File

@ -22,7 +22,7 @@
*/
package org.graalvm.compiler.hotspot.amd64;
import org.graalvm.compiler.core.amd64.AMD64SuitesProvider;
import org.graalvm.compiler.core.amd64.AMD64SuitesCreator;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.hotspot.lir.HotSpotZapRegistersPhase;
import org.graalvm.compiler.lir.phases.LIRSuites;
@ -30,9 +30,9 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plu
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
public class AMD64HotSpotSuitesProvider extends AMD64SuitesProvider {
public class AMD64HotSpotSuitesCreator extends AMD64SuitesCreator {
public AMD64HotSpotSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
public AMD64HotSpotSuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) {
super(compilerConfiguration, plugins);
}

View File

@ -27,12 +27,13 @@ import java.util.Set;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.sparc.SPARCAddressLowering;
import org.graalvm.compiler.core.sparc.SPARCSuitesProvider;
import org.graalvm.compiler.core.sparc.SPARCSuitesCreator;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
@ -123,7 +124,7 @@ public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory {
*/
protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins,
Replacements replacements) {
return new HotSpotSuitesProvider(new SPARCSuitesProvider(compilerConfiguration, plugins), config, runtime, new SPARCAddressLowering());
return new AddressLoweringHotSpotSuitesProvider(new SPARCSuitesCreator(compilerConfiguration, plugins), config, runtime, new SPARCAddressLowering());
}
protected SPARCHotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {

View File

@ -22,14 +22,34 @@
*/
package org.graalvm.compiler.hotspot.test;
import java.lang.annotation.Annotation;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import javax.management.Attribute;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.Assumptions;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ExceptionHandler;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.LineNumberTable;
import jdk.vm.ci.meta.LocalVariableTable;
import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
import jdk.vm.ci.meta.SpeculationLog;
import org.graalvm.compiler.debug.GraalDebugConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalMBean;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.util.EconomicMap;
@ -57,7 +77,7 @@ public class HotSpotGraalMBeanTest {
}
assertNull("The platformMBeanServer isn't initialized now", field.get(null));
HotSpotGraalMBean bean = HotSpotGraalMBean.create();
HotSpotGraalMBean bean = HotSpotGraalMBean.create(null);
assertNotNull("Bean created", bean);
assertNull("It is not registered yet", bean.ensureRegistered(true));
@ -82,7 +102,7 @@ public class HotSpotGraalMBeanTest {
assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer());
HotSpotGraalMBean realBean = HotSpotGraalMBean.create();
HotSpotGraalMBean realBean = HotSpotGraalMBean.create(null);
assertNotNull("Bean is registered", name = realBean.ensureRegistered(false));
final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
@ -124,7 +144,7 @@ public class HotSpotGraalMBeanTest {
assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer());
HotSpotGraalMBean realBean = HotSpotGraalMBean.create();
HotSpotGraalMBean realBean = HotSpotGraalMBean.create(null);
OptionValues original = new OptionValues(EconomicMap.create());
@ -153,4 +173,533 @@ public class HotSpotGraalMBeanTest {
}
@Test
public void dumpOperation() throws Exception {
Field field = null;
try {
field = stopMBeanServer();
} catch (Exception ex) {
if (ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
// skip on JDK9
return;
}
}
assertNull("The platformMBeanServer isn't initialized now", field.get(null));
ObjectName name;
assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer());
HotSpotGraalMBean realBean = HotSpotGraalMBean.create(null);
assertNotNull("Bean is registered", name = realBean.ensureRegistered(false));
final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectInstance bean = server.getObjectInstance(name);
assertNotNull("Bean is registered", bean);
MBeanInfo info = server.getMBeanInfo(name);
assertNotNull("Info is found", info);
final MBeanOperationInfo[] arr = info.getOperations();
assertEquals("Currently three overloads", 3, arr.length);
MBeanOperationInfo dumpOp = null;
for (int i = 0; i < arr.length; i++) {
assertEquals("dumpMethod", arr[i].getName());
if (arr[i].getSignature().length == 3) {
dumpOp = arr[i];
}
}
assertNotNull("three args variant found", dumpOp);
server.invoke(name, "dumpMethod", new Object[]{
"java.util.Arrays", "asList", ":3"
}, null);
MBeanAttributeInfo dump = findAttributeInfo("Dump", info);
Attribute dumpTo1 = new Attribute(dump.getName(), "");
server.setAttribute(name, dumpTo1);
Object after = server.getAttribute(name, dump.getName());
assertEquals("", after);
OptionValues empty = new OptionValues(EconomicMap.create());
OptionValues unsetDump = realBean.optionsFor(empty, null);
final OptionValues forMethod = realBean.optionsFor(unsetDump, new MockResolvedJavaMethod());
assertNotSame(unsetDump, forMethod);
Object nothing = unsetDump.getMap().get(GraalDebugConfig.Options.Dump);
assertEquals("Empty string", "", nothing);
Object specialValue = forMethod.getMap().get(GraalDebugConfig.Options.Dump);
assertEquals(":3", specialValue);
OptionValues normalMethod = realBean.optionsFor(unsetDump, null);
Object noSpecialValue = normalMethod.getMap().get(GraalDebugConfig.Options.Dump);
assertEquals("Empty string", "", noSpecialValue);
}
private static class MockResolvedJavaMethod implements HotSpotResolvedJavaMethod {
MockResolvedJavaMethod() {
}
@Override
public boolean isCallerSensitive() {
throw new UnsupportedOperationException();
}
@Override
public HotSpotResolvedObjectType getDeclaringClass() {
return new MockResolvedObjectType();
}
@Override
public boolean isForceInline() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasReservedStackAccess() {
throw new UnsupportedOperationException();
}
@Override
public void setNotInlineable() {
throw new UnsupportedOperationException();
}
@Override
public boolean ignoredBySecurityStackWalk() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasCompiledCode() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasCompiledCodeAtLevel(int level) {
throw new UnsupportedOperationException();
}
@Override
public int vtableEntryOffset(ResolvedJavaType resolved) {
throw new UnsupportedOperationException();
}
@Override
public int intrinsicId() {
throw new UnsupportedOperationException();
}
@Override
public int allocateCompileId(int entryBCI) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasCodeAtLevel(int entryBCI, int level) {
throw new UnsupportedOperationException();
}
@Override
public byte[] getCode() {
throw new UnsupportedOperationException();
}
@Override
public int getCodeSize() {
throw new UnsupportedOperationException();
}
@Override
public int getMaxLocals() {
throw new UnsupportedOperationException();
}
@Override
public int getMaxStackSize() {
throw new UnsupportedOperationException();
}
@Override
public boolean isSynthetic() {
throw new UnsupportedOperationException();
}
@Override
public boolean isVarArgs() {
throw new UnsupportedOperationException();
}
@Override
public boolean isBridge() {
throw new UnsupportedOperationException();
}
@Override
public boolean isClassInitializer() {
throw new UnsupportedOperationException();
}
@Override
public boolean isConstructor() {
throw new UnsupportedOperationException();
}
@Override
public boolean canBeStaticallyBound() {
throw new UnsupportedOperationException();
}
@Override
public ExceptionHandler[] getExceptionHandlers() {
throw new UnsupportedOperationException();
}
@Override
public StackTraceElement asStackTraceElement(int bci) {
throw new UnsupportedOperationException();
}
@Override
public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
throw new UnsupportedOperationException();
}
@Override
public void reprofile() {
throw new UnsupportedOperationException();
}
@Override
public ConstantPool getConstantPool() {
throw new UnsupportedOperationException();
}
@Override
public Annotation[][] getParameterAnnotations() {
throw new UnsupportedOperationException();
}
@Override
public Type[] getGenericParameterTypes() {
throw new UnsupportedOperationException();
}
@Override
public boolean canBeInlined() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasNeverInlineDirective() {
throw new UnsupportedOperationException();
}
@Override
public boolean shouldBeInlined() {
throw new UnsupportedOperationException();
}
@Override
public LineNumberTable getLineNumberTable() {
throw new UnsupportedOperationException();
}
@Override
public LocalVariableTable getLocalVariableTable() {
throw new UnsupportedOperationException();
}
@Override
public Constant getEncoding() {
throw new UnsupportedOperationException();
}
@Override
public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
throw new UnsupportedOperationException();
}
@Override
public SpeculationLog getSpeculationLog() {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return "asList";
}
@Override
public Signature getSignature() {
throw new UnsupportedOperationException();
}
@Override
public int getModifiers() {
throw new UnsupportedOperationException();
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
throw new UnsupportedOperationException();
}
@Override
public Annotation[] getAnnotations() {
throw new UnsupportedOperationException();
}
@Override
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
}
@Override
public boolean isIntrinsicCandidate() {
return true;
}
private static class MockResolvedObjectType implements HotSpotResolvedObjectType {
MockResolvedObjectType() {
}
@Override
public long getFingerprint() {
return 0L;
}
@Override
public HotSpotResolvedObjectType getArrayClass() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaType getComponentType() {
throw new UnsupportedOperationException();
}
@Override
public Assumptions.AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() {
throw new UnsupportedOperationException();
}
@Override
public HotSpotResolvedObjectType getSuperclass() {
throw new UnsupportedOperationException();
}
@Override
public HotSpotResolvedObjectType[] getInterfaces() {
throw new UnsupportedOperationException();
}
@Override
public HotSpotResolvedObjectType getSupertype() {
throw new UnsupportedOperationException();
}
@Override
public HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType) {
throw new UnsupportedOperationException();
}
@Override
public ConstantPool getConstantPool() {
throw new UnsupportedOperationException();
}
@Override
public int instanceSize() {
throw new UnsupportedOperationException();
}
@Override
public int getVtableLength() {
throw new UnsupportedOperationException();
}
@Override
public Assumptions.AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) {
throw new UnsupportedOperationException();
}
@Override
public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) {
throw new UnsupportedOperationException();
}
@Override
public Constant klass() {
throw new UnsupportedOperationException();
}
@Override
public boolean isPrimaryType() {
throw new UnsupportedOperationException();
}
@Override
public int superCheckOffset() {
throw new UnsupportedOperationException();
}
@Override
public long prototypeMarkWord() {
throw new UnsupportedOperationException();
}
@Override
public int layoutHelper() {
throw new UnsupportedOperationException();
}
@Override
public HotSpotResolvedObjectType getEnclosingType() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaMethod getClassInitializer() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasFinalizer() {
throw new UnsupportedOperationException();
}
@Override
public Assumptions.AssumptionResult<Boolean> hasFinalizableSubclass() {
throw new UnsupportedOperationException();
}
@Override
public boolean isInterface() {
throw new UnsupportedOperationException();
}
@Override
public boolean isInstanceClass() {
throw new UnsupportedOperationException();
}
@Override
public boolean isInitialized() {
throw new UnsupportedOperationException();
}
@Override
public void initialize() {
throw new UnsupportedOperationException();
}
@Override
public boolean isLinked() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAssignableFrom(ResolvedJavaType other) {
throw new UnsupportedOperationException();
}
@Override
public boolean isInstance(JavaConstant obj) {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaType getSingleImplementor() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaField[] getStaticFields() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedKind) {
throw new UnsupportedOperationException();
}
@Override
public String getSourceFileName() {
throw new UnsupportedOperationException();
}
@Override
public boolean isLocal() {
throw new UnsupportedOperationException();
}
@Override
public boolean isMember() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaMethod[] getDeclaredConstructors() {
throw new UnsupportedOperationException();
}
@Override
public ResolvedJavaMethod[] getDeclaredMethods() {
throw new UnsupportedOperationException();
}
@Override
public boolean isCloneableWithAllocation() {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return "Ljava/util/Arrays;";
}
@Override
public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
throw new UnsupportedOperationException();
}
@Override
public int getModifiers() {
throw new UnsupportedOperationException();
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
throw new UnsupportedOperationException();
}
@Override
public Annotation[] getAnnotations() {
throw new UnsupportedOperationException();
}
@Override
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
}
}
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.test;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase;
import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.junit.Assert;
import org.junit.Test;
public class ReplaceConstantNodesPhaseTest extends HotSpotGraalCompilerTest {
private final GraalHotSpotVMConfig config = runtime().getVMConfig();
@Override
protected Plugins getDefaultGraphBuilderPlugins() {
Plugins plugins = super.getDefaultGraphBuilderPlugins();
plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
return plugins;
}
public static class X {
public static int x;
public static int y;
public static int z;
public static Object o;
}
public static class Y extends X {
public static int a;
public static int b;
}
public static int a;
public static void assignFields() {
X.x = 1;
X.y = 2;
X.z = 3;
}
public static void assignFieldsInBranches(boolean x) {
if (x) {
X.y = 1;
} else {
X.z = 2;
}
}
public static void assignFieldsWithDominatingInit(boolean x) {
X.x = 1;
if (x) {
X.y = 2;
} else {
X.z = 3;
}
}
public static void assignString() {
X.o = "foo";
}
public static void assignToParentAndChild() {
Y.a = 1;
X.x = 2;
}
public static void assignToThis() {
a = 1;
}
public static void assignFieldsWithDominatingInitOfParent(boolean x) {
Y.a = 1;
if (x) {
X.y = 2;
} else {
X.z = 3;
}
Y.b = 4;
}
private void test(String name, int expectedInits, int expectedResolves, int expectedLoads) {
StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true));
HighTierContext highTierContext = getDefaultHighTierContext();
CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
new EliminateRedundantInitializationPhase().apply(graph, highTierContext);
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
new LoadJavaMirrorWithKlassPhase(config).apply(graph, highTierContext);
new ReplaceConstantNodesPhase(false).apply(graph, highTierContext);
Assert.assertEquals(expectedInits, graph.getNodes().filter(InitializeKlassNode.class).count());
Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveConstantNode.class).count());
Assert.assertEquals(expectedLoads, graph.getNodes().filter(LoadConstantIndirectlyNode.class).count());
}
@Test
public void test1() {
test("assignFields", 1, 0, 0);
}
@Test
public void test2() {
test("assignFieldsWithDominatingInit", 1, 0, 0);
}
@Test
public void test3() {
test("assignString", 1, 1, 0);
}
@Test
public void test4() {
test("assignToParentAndChild", 1, 1, 0);
}
@Test
public void test5() {
test("assignToThis", 0, 0, 1);
}
@Test
public void test6() {
test("assignFieldsWithDominatingInitOfParent", 1, 1, 0);
}
@Test
public void test7() {
test("assignFieldsInBranches", 2, 1, 0);
}
}

View File

@ -295,11 +295,13 @@ public class CompilationTask {
// Log a compilation event.
EventProvider.CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
// If there is already compiled code for this method on our level we simply return.
// JVMCI compiles are always at the highest compile level, even in non-tiered mode so we
// only need to check for that value.
if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) {
return null;
if (installAsDefault) {
// If there is already compiled code for this method on our level we simply return.
// JVMCI compiles are always at the highest compile level, even in non-tiered mode so we
// only need to check for that value.
if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) {
return HotSpotCompilationRequestResult.failure("Already compiled", false);
}
}
RetryableCompilation compilation = new RetryableCompilation(compilationEvent);

View File

@ -20,25 +20,21 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot;
package org.graalvm.compiler.core.aarch64;
import jdk.vm.ci.code.CompiledCode;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
public interface HotSpotCodeCacheListener {
/**
* Notifies this object on successful install into the CodeCache.
*
* @param codeCache the code cache into which the code was installed
* @param installedCode the code that was installed
* @param compiledCode the compiled code from which {@code installedCode} was produced
*/
default void notifyInstall(HotSpotCodeCacheProvider codeCache, InstalledCode installedCode, CompiledCode compiledCode) {
public class AArch64AddressLowering extends AddressLowering {
@Override
public AddressNode lower(ValueNode address) {
return lower(address, null);
}
@Override
public AddressNode lower(ValueNode base, ValueNode offset) {
AArch64AddressNode ret = new AArch64AddressNode(base, offset);
// TODO improve
return base.graph().unique(ret);
}
}

View File

@ -81,11 +81,10 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
private final CompilationCounters compilationCounters;
private final BootstrapWatchDog bootstrapWatchDog;
HotSpotGraalCompiler(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime) {
HotSpotGraalCompiler(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, OptionValues options) {
this.jvmciRuntime = jvmciRuntime;
this.graalRuntime = graalRuntime;
// It is sufficient to have one compilation counter object per Graal compiler object.
OptionValues options = graalRuntime.getOptions();
this.compilationCounters = Options.CompilationCountLimit.getValue(options) > 0 ? new CompilationCounters(options) : null;
this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !GraalDebugConfig.Options.BootstrapInitializeOnly.getValue(options) ? BootstrapWatchDog.maybeCreate(graalRuntime) : null;
}
@ -96,8 +95,12 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
}
@Override
@SuppressWarnings("try")
public CompilationRequestResult compileMethod(CompilationRequest request) {
return compileMethod(request, true);
}
@SuppressWarnings("try")
CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault) {
if (graalRuntime.isShutdown()) {
return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false);
}
@ -124,8 +127,8 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
}
// Ensure a debug configuration for this thread is initialized
DebugEnvironment.ensureInitialized(options, graalRuntime.getHostProviders().getSnippetReflection());
CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, true, options);
CompilationRequestResult r = null;
CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, installAsDefault, options);
CompilationRequestResult r;
try (DebugConfigScope dcs = Debug.setConfig(new TopLevelDebugConfig());
Debug.Scope s = Debug.methodMetricsScope("HotSpotGraalCompiler", MethodMetricsRootScopeInfo.create(method), true, method)) {
r = task.runCompilation();

View File

@ -128,7 +128,7 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
HotSpotJVMCIRuntime jvmciRuntime = (HotSpotJVMCIRuntime) runtime;
try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(jvmciRuntime, compilerConfigurationFactory, options);
return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime);
return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime, graalRuntime.getOptions());
}
}

View File

@ -23,9 +23,13 @@
package org.graalvm.compiler.hotspot;
import java.lang.management.ManagementFactory;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
@ -34,31 +38,51 @@ import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.MetaUtil;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.runtime.JVMCI;
import org.graalvm.compiler.debug.GraalDebugConfig;
import org.graalvm.compiler.options.OptionDescriptor;
import org.graalvm.compiler.options.OptionDescriptors;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.options.OptionsParser;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.EconomicSet;
import org.graalvm.util.Equivalence;
import org.graalvm.util.UnmodifiableEconomicMap;
public final class HotSpotGraalMBean implements DynamicMBean {
private static Object mBeanServerField;
private final HotSpotGraalCompiler compiler;
private final OptionValues options;
private final EconomicMap<OptionKey<?>, Object> changes;
private final EconomicSet<Dump> methodDumps;
private volatile EconomicSet<Reference<ClassLoader>> loaders;
private ObjectName registered;
private OptionValues cachedOptions;
private HotSpotGraalMBean(OptionValues options) {
private HotSpotGraalMBean(HotSpotGraalCompiler compiler, OptionValues options) {
this.compiler = compiler;
this.options = options;
this.changes = EconomicMap.create();
this.methodDumps = EconomicSet.create();
EconomicSet<Reference<ClassLoader>> systemLoaderSet = EconomicSet.create(RefEquivalence.INSTANCE);
systemLoaderSet.add(new WeakReference<>(ClassLoader.getSystemClassLoader()));
this.loaders = systemLoaderSet;
}
private static boolean isMXServerOn() {
@ -82,9 +106,9 @@ public final class HotSpotGraalMBean implements DynamicMBean {
}
}
public static HotSpotGraalMBean create() {
public static HotSpotGraalMBean create(HotSpotGraalCompiler compiler) {
OptionValues options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
HotSpotGraalMBean mbean = new HotSpotGraalMBean(options);
HotSpotGraalMBean mbean = new HotSpotGraalMBean(compiler, options);
return mbean;
}
@ -111,14 +135,25 @@ public final class HotSpotGraalMBean implements DynamicMBean {
return registered;
}
@SuppressWarnings("unused")
public OptionValues optionsFor(OptionValues initialValues, ResolvedJavaMethod forMethod) {
ensureRegistered(true);
return currentMap(initialValues);
if (forMethod instanceof HotSpotResolvedJavaMethod) {
HotSpotResolvedObjectType type = ((HotSpotResolvedJavaMethod) forMethod).getDeclaringClass();
if (type instanceof HotSpotResolvedJavaType) {
Class<?> clazz = ((HotSpotResolvedJavaType) type).mirror();
Reference<ClassLoader> addNewRef = new WeakReference<>(clazz.getClassLoader());
if (!loaders.contains(addNewRef)) {
EconomicSet<Reference<ClassLoader>> newLoaders = EconomicSet.create(RefEquivalence.INSTANCE, loaders);
newLoaders.add(addNewRef);
this.loaders = newLoaders;
}
}
}
return currentMap(initialValues, forMethod);
}
private OptionValues currentMap(OptionValues initialValues) {
if (changes.isEmpty()) {
private OptionValues currentMap(OptionValues initialValues, ResolvedJavaMethod method) {
if (changes.isEmpty() && methodDumps.isEmpty()) {
return initialValues;
}
OptionValues current = cachedOptions;
@ -126,12 +161,23 @@ public final class HotSpotGraalMBean implements DynamicMBean {
current = new OptionValues(initialValues, changes);
cachedOptions = current;
}
if (method != null) {
for (Dump request : methodDumps) {
final String clazzName = method.getDeclaringClass().getName();
if (method.getName().equals(request.method) && clazzName.equals(request.clazz)) {
current = new OptionValues(current, GraalDebugConfig.Options.Dump, request.filter,
GraalDebugConfig.Options.PrintGraphHost, request.host,
GraalDebugConfig.Options.PrintBinaryGraphPort, request.port);
break;
}
}
}
return current;
}
@Override
public Object getAttribute(String attribute) {
UnmodifiableEconomicMap<OptionKey<?>, Object> map = currentMap(options).getMap();
UnmodifiableEconomicMap<OptionKey<?>, Object> map = currentMap(options, null).getMap();
for (OptionKey<?> k : map.getKeys()) {
if (k.getName().equals(attribute)) {
return map.get(k);
@ -185,9 +231,71 @@ public final class HotSpotGraalMBean implements DynamicMBean {
@Override
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
if ("dumpMethod".equals(actionName)) {
try {
String className = param(params, 0, "className", String.class, null);
String methodName = param(params, 1, "methodName", String.class, null);
String filter = param(params, 2, "filter", String.class, ":3");
String host = param(params, 3, "host", String.class, "localhost");
Number port = param(params, 4, "port", Number.class, 4445);
dumpMethod(className, methodName, filter, host, port.intValue());
} catch (Exception ex) {
throw new ReflectionException(ex);
}
}
return null;
}
private static <T> T param(Object[] arr, int index, String name, Class<T> type, T defaultValue) {
Object value = arr.length > index ? arr[index] : null;
if (value == null || (value instanceof String && ((String) value).isEmpty())) {
if (defaultValue == null) {
throw new IllegalArgumentException(name + " must be specified");
}
value = defaultValue;
}
if (type.isInstance(value)) {
return type.cast(value);
}
throw new IllegalArgumentException("Expecting " + type.getName() + " for " + name + " but was " + value);
}
public void dumpMethod(String className, String methodName, String filter, String host, int port) throws MBeanException {
String jvmName = MetaUtil.toInternalName(className);
methodDumps.add(new Dump(host, port, jvmName, methodName, filter));
ClassNotFoundException last = null;
EconomicSet<Class<?>> found = EconomicSet.create();
Iterator<Reference<ClassLoader>> it = loaders.iterator();
while (it.hasNext()) {
Reference<ClassLoader> ref = it.next();
ClassLoader loader = ref.get();
if (loader == null) {
it.remove();
continue;
}
try {
Class<?> clazz = Class.forName(className, false, loader);
if (found.add(clazz)) {
ResolvedJavaType type = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(clazz);
if (compiler != null) {
for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
if (methodName.equals(method.getName()) && method instanceof HotSpotResolvedJavaMethod) {
HotSpotResolvedJavaMethod hotSpotMethod = (HotSpotResolvedJavaMethod) method;
compiler.compileMethod(new HotSpotCompilationRequest(hotSpotMethod, -1, 0L), false);
}
}
}
}
} catch (ClassNotFoundException ex) {
last = ex;
}
}
if (found.isEmpty()) {
throw new MBeanException(last, "Cannot find class " + className + " to schedule recompilation");
}
}
@Override
public MBeanInfo getMBeanInfo() {
List<MBeanAttributeInfo> attrs = new ArrayList<>();
@ -196,11 +304,30 @@ public final class HotSpotGraalMBean implements DynamicMBean {
attrs.add(new MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
}
}
MBeanOperationInfo[] ops = {
new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{
new MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
}, "void", MBeanOperationInfo.ACTION),
new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{
new MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
new MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"),
}, "void", MBeanOperationInfo.ACTION),
new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{
new MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
new MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"),
new MBeanParameterInfo("host", "java.lang.String", "The host where the IGV tool is running at"),
new MBeanParameterInfo("port", "int", "The port where the IGV tool is listening at"),
}, "void", MBeanOperationInfo.ACTION)
};
return new MBeanInfo(
HotSpotGraalMBean.class.getName(),
"Graal",
attrs.toArray(new MBeanAttributeInfo[attrs.size()]),
null, null, null);
null, ops, null);
}
private static Iterable<OptionDescriptor> allOptionDescriptors() {
@ -213,4 +340,41 @@ public final class HotSpotGraalMBean implements DynamicMBean {
return arr;
}
private static final class Dump {
final String host;
final int port;
final String clazz;
final String method;
final String filter;
Dump(String host, int port, String clazz, String method, String filter) {
this.host = host;
this.port = port;
this.clazz = clazz;
this.method = method;
this.filter = filter;
}
}
private static final class RefEquivalence extends Equivalence {
static final Equivalence INSTANCE = new RefEquivalence();
private RefEquivalence() {
}
@Override
public boolean equals(Object a, Object b) {
Reference<?> refA = (Reference<?>) a;
Reference<?> refB = (Reference<?>) b;
return Objects.equals(refA.get(), refB.get());
}
@Override
public int hashCode(Object o) {
Reference<?> ref = (Reference<?>) o;
Object obj = ref.get();
return obj == null ? 0 : obj.hashCode();
}
}
}

View File

@ -130,10 +130,12 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
options = initialOptions;
}
this.mBean = HotSpotGraalMBean.create();
snippetCounterGroups = GraalOptions.SnippetCounters.getValue(options) ? new ArrayList<>() : null;
CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
HotSpotGraalCompiler compiler = new HotSpotGraalCompiler(jvmciRuntime, this, initialOptions);
this.mBean = HotSpotGraalMBean.create(compiler);
BackendMap backendMap = compilerConfigurationFactory.createBackendMap();
JVMCIBackend hostJvmciBackend = jvmciRuntime.getHostJVMCIBackend();
@ -261,12 +263,12 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
@Override
public OptionValues getOptions() {
return mBean == null ? options : mBean.optionsFor(options, null);
return mBean.optionsFor(options, null);
}
@Override
public OptionValues getOptions(ResolvedJavaMethod forMethod) {
return mBean == null ? options : mBean.optionsFor(options, forMethod);
return mBean.optionsFor(options, forMethod);
}
@Override

View File

@ -22,21 +22,29 @@
*/
package org.graalvm.compiler.hotspot;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.GraalDebugConfig;
import jdk.vm.ci.code.CompiledCode;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
import jdk.vm.ci.hotspot.HotSpotVMEventListener;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.GraalDebugConfig;
import org.graalvm.compiler.serviceprovider.GraalServices;
import java.util.ArrayList;
import java.util.List;
public class HotSpotGraalVMEventListener implements HotSpotVMEventListener {
private final HotSpotGraalRuntime runtime;
private List<HotSpotCodeCacheListener> listeners;
HotSpotGraalVMEventListener(HotSpotGraalRuntime runtime) {
this.runtime = runtime;
listeners = new ArrayList<>();
for (HotSpotCodeCacheListener listener : GraalServices.load(HotSpotCodeCacheListener.class)) {
listeners.add(listener);
}
}
@Override
@ -54,6 +62,9 @@ public class HotSpotGraalVMEventListener implements HotSpotVMEventListener {
if (Debug.isLogEnabled()) {
Debug.log("%s", codeCache.disassemble(installedCode));
}
for (HotSpotCodeCacheListener listener : listeners) {
listener.notifyInstall(codeCache, installedCode, compiledCode);
}
}
@Override

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Red Hat Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.meta;
import java.util.ListIterator;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.common.AddressLoweringPhase;
import org.graalvm.compiler.phases.common.ExpandLogicPhase;
import org.graalvm.compiler.phases.common.FixReadsPhase;
import org.graalvm.compiler.phases.tiers.LowTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
import org.graalvm.compiler.phases.tiers.SuitesCreator;
/**
* Subclass to factor out management of address lowering.
*/
public class AddressLoweringHotSpotSuitesProvider extends HotSpotSuitesProvider {
private final AddressLoweringPhase.AddressLowering addressLowering;
public AddressLoweringHotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime,
AddressLoweringPhase.AddressLowering addressLowering) {
super(defaultSuitesCreator, config, runtime);
this.addressLowering = addressLowering;
}
@Override
public Suites createSuites(OptionValues options) {
Suites suites = super.createSuites(options);
ListIterator<BasePhase<? super LowTierContext>> findPhase = suites.getLowTier().findPhase(FixReadsPhase.class);
if (findPhase == null) {
findPhase = suites.getLowTier().findPhase(ExpandLogicPhase.class);
}
findPhase.add(new AddressLoweringPhase(addressLowering));
return suites;
}
}

View File

@ -364,11 +364,17 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
} else if (n instanceof IdentityHashCodeNode) {
hashCodeSnippets.lower((IdentityHashCodeNode) n, tool);
} else if (n instanceof ResolveConstantNode) {
resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
}
} else if (n instanceof ResolveMethodAndLoadCountersNode) {
resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool);
if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool);
}
} else if (n instanceof InitializeKlassNode) {
resolveConstantSnippets.lower((InitializeKlassNode) n, tool);
if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
resolveConstantSnippets.lower((InitializeKlassNode) n, tool);
}
} else if (n instanceof ProfileNode) {
profileSnippets.lower((ProfileNode) n, tool);
} else {

View File

@ -52,16 +52,11 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.common.AddressLoweringPhase;
import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.ExpandLogicPhase;
import org.graalvm.compiler.phases.common.FixReadsPhase;
import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.common.inlining.InliningPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.LowTierContext;
import org.graalvm.compiler.phases.tiers.MidTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
import org.graalvm.compiler.phases.tiers.SuitesCreator;
@ -73,14 +68,12 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
protected final GraalHotSpotVMConfig config;
protected final HotSpotGraalRuntimeProvider runtime;
private final AddressLowering addressLowering;
private final SuitesCreator defaultSuitesCreator;
public HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, AddressLowering addressLowering) {
public HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime) {
this.defaultSuitesCreator = defaultSuitesCreator;
this.config = config;
this.runtime = runtime;
this.addressLowering = addressLowering;
this.defaultGraphBuilderSuite = createGraphBuilderSuite();
}
@ -95,14 +88,14 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
}
if (GeneratePIC.getValue(options)) {
// EliminateRedundantInitializationPhase must happen before the first lowering.
ListIterator<BasePhase<? super HighTierContext>> highTierLowering = ret.getHighTier().findPhase(LoweringPhase.class);
highTierLowering.previous();
highTierLowering.add(new EliminateRedundantInitializationPhase());
if (HotSpotAOTProfilingPlugin.Options.TieredAOT.getValue(options)) {
highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue(options)));
}
ret.getMidTier().findPhase(LoopSafepointInsertionPhase.class).add(new ReplaceConstantNodesPhase());
ListIterator<BasePhase<? super MidTierContext>> midTierLowering = ret.getMidTier().findPhase(LoweringPhase.class);
midTierLowering.add(new ReplaceConstantNodesPhase());
// Replace inlining policy
ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(InliningPhase.class);
@ -117,12 +110,6 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config));
}
ListIterator<BasePhase<? super LowTierContext>> findPhase = ret.getLowTier().findPhase(FixReadsPhase.class);
if (findPhase == null) {
findPhase = ret.getLowTier().findPhase(ExpandLogicPhase.class);
}
findPhase.add(new AddressLoweringPhase(addressLowering));
return ret;
}

View File

@ -22,18 +22,21 @@
*/
package org.graalvm.compiler.hotspot.nodes.aot;
import static org.graalvm.compiler.nodeinfo.InputType.Memory;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
import org.graalvm.api.word.LocationIdentity;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable {
@NodeInfo(cycles = CYCLES_4, size = SIZE_16, allowedUsageTypes = {Memory})
public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single {
public static final NodeClass<InitializeKlassNode> TYPE = NodeClass.create(InitializeKlassNode.class);
@Input ValueNode value;
@ -56,4 +59,9 @@ public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implement
public boolean canDeoptimize() {
return true;
}
@Override
public LocationIdentity getLocationIdentity() {
return LocationIdentity.any();
}
}

View File

@ -28,13 +28,13 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
public class ResolveConstantNode extends FloatingNode implements Lowerable {
public class ResolveConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable {
public static final NodeClass<ResolveConstantNode> TYPE = NodeClass.create(ResolveConstantNode.class);
@Input ValueNode value;
@ -64,4 +64,9 @@ public class ResolveConstantNode extends FloatingNode implements Lowerable {
public HotSpotConstantLoadAction action() {
return action;
}
@Override
public boolean canDeoptimize() {
return true;
}
}

View File

@ -110,5 +110,4 @@ public class ResolveConstantStubCall extends DeoptimizingStubCall implements Can
}
gen.setResult(this, result);
}
}

View File

@ -28,15 +28,15 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
public class ResolveMethodAndLoadCountersNode extends FloatingNode implements Lowerable {
public class ResolveMethodAndLoadCountersNode extends DeoptimizingFixedWithNextNode implements Lowerable {
public static final NodeClass<ResolveMethodAndLoadCountersNode> TYPE = NodeClass.create(ResolveMethodAndLoadCountersNode.class);
ResolvedJavaMethod method;
@ -60,4 +60,9 @@ public class ResolveMethodAndLoadCountersNode extends FloatingNode implements Lo
public ValueNode getHub() {
return hub;
}
@Override
public boolean canDeoptimize() {
return true;
}
}

View File

@ -22,10 +22,12 @@
*/
package org.graalvm.compiler.hotspot.phases.aot;
import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes;
import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
import java.util.HashSet;
import java.util.List;
import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
@ -35,11 +37,13 @@ import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.ResolvedJavaType;
import org.graalvm.compiler.core.common.cfg.BlockMap;
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeMap;
import org.graalvm.compiler.hotspot.FingerprintUtil;
import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
@ -49,14 +53,21 @@ import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.graalvm.util.EconomicMap;
public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
private static final HashSet<Class<?>> builtIns = new HashSet<>();
private final boolean verifyFingerprints;
static {
builtIns.add(Boolean.class);
@ -91,6 +102,14 @@ public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
// @formatter:on
}
private static boolean anyUsagesNeedReplacement(ConstantNode node) {
return node.usages().filter(n -> !isReplacementNode(n)).isNotEmpty();
}
private static boolean anyUsagesNeedReplacement(LoadMethodCountersNode node) {
return node.usages().filter(n -> !(n instanceof ResolveMethodAndLoadCountersNode)).isNotEmpty();
}
private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) {
if (type.isArray()) {
if (type.getElementalType().isPrimitive()) {
@ -101,80 +120,223 @@ public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0;
}
private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) {
/**
* Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with indirection.
*
* @param graph
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
* resolution.
*/
private void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) {
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
if (type != null) {
if (checkForBadFingerprint(type)) {
if (verifyFingerprints && checkForBadFingerprint(type)) {
throw new GraalError("Type with bad fingerprint: " + type);
}
assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
ValueNode replacement;
if (type.isArray() && type.getComponentType().isPrimitive()) {
// Special case for primitive arrays. The AOT runtime pre-resolves them, so we may
// omit the resolution call.
replacement = new LoadConstantIndirectlyNode(node);
} else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) {
// If it's a supertype of or the same class that declares the top method, we are
// guaranteed to have it resolved already. If it's an interface, we just test for
// equality.
replacement = new LoadConstantIndirectlyNode(node);
} else if (builtIns.contains(type.mirror())) {
// Special case of klass constants that come from {@link BoxingSnippets}.
replacement = new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE);
} else {
replacement = new ResolveConstantNode(node);
replaceWithInitialization(graph, node);
if (anyUsagesNeedReplacement(node)) {
replaceWithResolution(graph, node);
}
node.replaceAtUsages(graph.addOrUnique(replacement), n -> !isReplacementNode(n));
} else {
throw new GraalError("Unsupported metaspace constant type: " + type);
}
}
/**
* Find the lowest dominating {@link FixedWithNextNode} before given node.
*
* @param graph
* @param node
* @return the last {@link FixedWithNextNode} that is scheduled before node.
*/
private static FixedWithNextNode findFixedWithNextBefore(StructuredGraph graph, Node node) {
ScheduleResult schedule = graph.getLastSchedule();
NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
Block block = nodeToBlock.get(node);
FixedWithNextNode result = null;
for (Node n : blockToNodes.get(block)) {
if (n instanceof FixedWithNextNode) {
result = (FixedWithNextNode) n;
}
if (n.equals(node)) {
break;
}
}
assert result != null;
return result;
}
/**
* Try to find dominating {@link InitializeKlassNode} that can be reused.
*
* @param graph
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
* resolution.
*/
private static void replaceWithInitialization(StructuredGraph graph, ConstantNode node) {
ScheduleResult schedule = graph.getLastSchedule();
NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
EconomicMap<Block, Node> blockToInit = EconomicMap.create();
for (Node n : node.usages().filter(InitializeKlassNode.class)) {
blockToInit.put(nodeToBlock.get(n), n);
}
for (Node use : node.usages().filter(n -> !isReplacementNode(n)).snapshot()) {
boolean replaced = false;
Block b = nodeToBlock.get(use);
InitializeKlassNode i = (InitializeKlassNode) blockToInit.get(b);
if (i != null) {
// There is an initialization in the same block as the use, look if the use is
// scheduled after it.
for (Node n : blockToNodes.get(b)) {
if (n.equals(use)) {
// Usage is before initialization, can't use it
break;
}
if (n.equals(i)) {
use.replaceFirstInput(node, i);
replaced = true;
break;
}
}
}
if (!replaced) {
// Look for dominating blocks that have initializations
for (Block d : blockToInit.getKeys()) {
if (strictlyDominates(d, b)) {
use.replaceFirstInput(node, blockToInit.get(d));
break;
}
}
}
}
}
/**
* Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} or
* {@link ResolveConstantNode}.
*
* @param graph
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
* resolution.
*/
private static void replaceWithResolution(StructuredGraph graph, ConstantNode node) {
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
ValueNode replacement;
if (type.isArray() && type.getComponentType().isPrimitive()) {
// Special case for primitive arrays. The AOT runtime pre-resolves them, so we may
// omit the resolution call.
replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node));
} else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) {
// If it's a supertype of or the same class that declares the top method, we are
// guaranteed to have it resolved already. If it's an interface, we just test for
// equality.
replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node));
} else {
FixedWithNextNode fixedReplacement;
if (builtIns.contains(type.mirror())) {
// Special case of klass constants that come from {@link BoxingSnippets}.
fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE));
} else {
fixedReplacement = graph.add(new ResolveConstantNode(node));
}
graph.addAfterFixed(findFixedWithNextBefore(graph, node), fixedReplacement);
replacement = fixedReplacement;
}
node.replaceAtUsages(replacement, n -> !isReplacementNode(n));
}
/**
* Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we
* support only strings.
*
* @param graph
* @param node {@link ConstantNode} containing a {@link HotSpotObjectConstant} that needs
* resolution.
*/
private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) {
HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant();
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType();
if (type.mirror().equals(String.class)) {
assert !constant.isCompressed() : "No support for replacing compressed oop constants";
ValueNode replacement = graph.unique(new ResolveConstantNode(node));
FixedWithNextNode replacement = graph.add(new ResolveConstantNode(node));
graph.addAfterFixed(findFixedWithNextBefore(graph, node), replacement);
node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode));
} else {
throw new GraalError("Unsupported object constant type: " + type);
}
}
/**
* Replace {@link LoadMethodCountersNode} with indirect load
* {@link ResolveMethodAndLoadCountersNode}, expose a klass constant of the holder.
*
* @param graph
* @param node
* @param context
*/
private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) {
ResolvedJavaType type = node.getMethod().getDeclaringClass();
Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull());
ConstantReflectionProvider constantReflection = context.getConstantReflection();
ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph);
ValueNode replacement = graph.unique(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint));
FixedWithNextNode replacement = graph.add(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint));
graph.addAfterFixed(findFixedWithNextBefore(graph, node), replacement);
node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode));
}
/**
* Replace {@link LoadMethodCountersNode} with {@link ResolveMethodAndLoadCountersNode}, expose
* klass constants.
*
* @param graph
* @param context
*/
private static void replaceLoadMethodCounters(StructuredGraph graph, PhaseContext context) {
new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) {
if (anyUsagesNeedReplacement(node)) {
handleLoadMethodCounters(graph, node, context);
}
}
}
/**
* Replace object and klass constants with resolution nodes or reuse preceding initializations.
*
* @param graph
*/
private void replaceKlassesAndObjects(StructuredGraph graph) {
new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
for (ConstantNode node : getConstantNodes(graph)) {
Constant constant = node.asConstant();
if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) {
handleHotSpotMetaspaceConstant(graph, node);
} else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) {
handleHotSpotObjectConstant(graph, node);
}
}
}
@Override
protected void run(StructuredGraph graph, PhaseContext context) {
// Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
// constants.
for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) {
handleLoadMethodCounters(graph, node, context);
}
replaceLoadMethodCounters(graph, context);
// Replace object and klass constants (including the ones added in the previous pass) with
// resolution nodes.
for (ConstantNode node : getConstantNodes(graph)) {
Constant constant = node.asConstant();
if (constant instanceof HotSpotMetaspaceConstant) {
handleHotSpotMetaspaceConstant(graph, node);
} else if (constant instanceof HotSpotObjectConstant) {
handleHotSpotObjectConstant(graph, node);
}
}
replaceKlassesAndObjects(graph);
}
@Override
@ -182,4 +344,11 @@ public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
return false;
}
public ReplaceConstantNodesPhase() {
this(true);
}
public ReplaceConstantNodesPhase(boolean verifyFingerprints) {
this.verifyFingerprints = verifyFingerprints;
}
}

View File

@ -49,7 +49,6 @@ import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
import org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.Counters;
import org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.Hints;
import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizeNode;
@ -147,12 +146,6 @@ public class InstanceOfSnippets implements Snippets {
return trueValue;
}
@Snippet
public static Object instanceofExactPIC(Object object, KlassPointer exactHub, Object trueValue, Object falseValue, @ConstantParameter Counters counters) {
KlassPointer exactHubPIC = ResolveConstantSnippets.resolveKlassConstant(exactHub);
return instanceofExact(object, exactHubPIC, trueValue, falseValue, counters);
}
/**
* A test against a primary type.
*/
@ -172,12 +165,6 @@ public class InstanceOfSnippets implements Snippets {
return trueValue;
}
@Snippet
public static Object instanceofPrimaryPIC(KlassPointer hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue, @ConstantParameter Counters counters) {
KlassPointer resolvedHub = ResolveConstantSnippets.resolveKlassConstant(hub);
return instanceofPrimary(resolvedHub, object, superCheckOffset, trueValue, falseValue, counters);
}
/**
* A test against a restricted secondary type type.
*/
@ -207,13 +194,6 @@ public class InstanceOfSnippets implements Snippets {
return trueValue;
}
@Snippet
public static Object instanceofSecondaryPIC(KlassPointer hub, Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue,
Object falseValue, @ConstantParameter Counters counters) {
KlassPointer resolvedHub = ResolveConstantSnippets.resolveKlassConstant(hub);
return instanceofSecondary(resolvedHub, object, hints, hintIsPositive, trueValue, falseValue, counters);
}
/**
* Type test used when the type being tested against is not known at compile time.
*/
@ -272,11 +252,8 @@ public class InstanceOfSnippets implements Snippets {
private final SnippetInfo instanceofWithProfile = snippet(InstanceOfSnippets.class, "instanceofWithProfile");
private final SnippetInfo instanceofExact = snippet(InstanceOfSnippets.class, "instanceofExact");
private final SnippetInfo instanceofExactPIC = snippet(InstanceOfSnippets.class, "instanceofExactPIC");
private final SnippetInfo instanceofPrimary = snippet(InstanceOfSnippets.class, "instanceofPrimary");
private final SnippetInfo instanceofPrimaryPIC = snippet(InstanceOfSnippets.class, "instanceofPrimaryPIC");
private final SnippetInfo instanceofSecondary = snippet(InstanceOfSnippets.class, "instanceofSecondary", SECONDARY_SUPER_CACHE_LOCATION);
private final SnippetInfo instanceofSecondaryPIC = snippet(InstanceOfSnippets.class, "instanceofSecondaryPIC", SECONDARY_SUPER_CACHE_LOCATION);
private final SnippetInfo instanceofDynamic = snippet(InstanceOfSnippets.class, "instanceofDynamic", SECONDARY_SUPER_CACHE_LOCATION);
private final SnippetInfo isAssignableFrom = snippet(InstanceOfSnippets.class, "isAssignableFrom", SECONDARY_SUPER_CACHE_LOCATION);
@ -316,20 +293,17 @@ public class InstanceOfSnippets implements Snippets {
args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs);
args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(JavaKind.Boolean), hints.isPositive);
} else if (hintInfo.exact != null) {
SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? instanceofExactPIC : instanceofExact;
args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args = new Arguments(instanceofExact, graph.getGuardsStage(), tool.getLoweringStage());
args.add("object", object);
args.add("exactHub", ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hintInfo.exact).klass(), providers.getMetaAccess(), graph));
} else if (type.isPrimaryType()) {
SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? instanceofPrimaryPIC : instanceofPrimary;
args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args = new Arguments(instanceofPrimary, graph.getGuardsStage(), tool.getLoweringStage());
args.add("hub", hub);
args.add("object", object);
args.addConst("superCheckOffset", type.superCheckOffset());
} else {
Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph);
SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? instanceofSecondaryPIC : instanceofSecondary;
args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args = new Arguments(instanceofSecondary, graph.getGuardsStage(), tool.getLoweringStage());
args.add("hub", hub);
args.add("object", object);
args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs);

View File

@ -149,7 +149,7 @@ public class ResolveConstantSnippets implements Snippets {
args.add("constant", value);
SnippetTemplate template = template(args);
template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, tool, args);
template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
assert resolveConstantNode.hasNoUsages();
if (!resolveConstantNode.isDeleted()) {
@ -187,7 +187,7 @@ public class ResolveConstantSnippets implements Snippets {
args.add("method", method);
args.add("klassHint", resolveMethodAndLoadCountersNode.getHub());
SnippetTemplate template = template(args);
template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, tool, args);
template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args);
assert resolveMethodAndLoadCountersNode.hasNoUsages();
if (!resolveMethodAndLoadCountersNode.isDeleted()) {

View File

@ -1422,7 +1422,7 @@ public class BytecodeParser implements GraphBuilderContext {
@Override
public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
BytecodeParser intrinsicCallSiteParser = getNonIntrinsicAncestor();
boolean withExceptionEdge = intrinsicCallSiteParser == null ? false : intrinsicCallSiteParser.omitInvokeExceptionEdge(null);
boolean withExceptionEdge = intrinsicCallSiteParser == null ? !omitInvokeExceptionEdge(null) : !intrinsicCallSiteParser.omitInvokeExceptionEdge(null);
createNonInlinedInvoke(withExceptionEdge, bci(), callTarget, resultType);
}

View File

@ -31,11 +31,11 @@ import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
public class DefaultSuitesProvider extends SuitesProviderBase {
public class DefaultSuitesCreator extends SuitesProviderBase {
private final CompilerConfiguration compilerConfiguration;
public DefaultSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
public DefaultSuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) {
super();
this.defaultGraphBuilderSuite = createGraphBuilderSuite(plugins);
this.compilerConfiguration = compilerConfiguration;

View File

@ -46,20 +46,20 @@ public final class AArch64AddressValue extends CompositeValue {
@Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
@Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue offset;
private final int immediate;
private final int displacement;
/**
* Whether register offset should be scaled or not.
*/
private final boolean scaled;
private final int scaleFactor;
private final AddressingMode addressingMode;
public AArch64AddressValue(ValueKind<?> kind, AllocatableValue base, AllocatableValue offset, int immediate, boolean scaled, AddressingMode addressingMode) {
public AArch64AddressValue(ValueKind<?> kind, AllocatableValue base, AllocatableValue offset, int displacement, int scaleFactor, AddressingMode addressingMode) {
super(kind);
this.base = base;
this.offset = offset;
this.immediate = immediate;
this.scaled = scaled;
this.displacement = displacement;
this.scaleFactor = scaleFactor;
this.addressingMode = addressingMode;
}
@ -79,12 +79,16 @@ public final class AArch64AddressValue extends CompositeValue {
return offset;
}
public int getImmediate() {
return immediate;
public int getDisplacement() {
return displacement;
}
public boolean isScaled() {
return scaled;
return scaleFactor != 1;
}
public int getScaleFactor() {
return scaleFactor;
}
public AddressingMode getAddressingMode() {
@ -95,7 +99,7 @@ public final class AArch64AddressValue extends CompositeValue {
Register baseReg = toRegister(base);
Register offsetReg = toRegister(offset);
AArch64Assembler.ExtendType extendType = addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET ? ExtendType.SXTW : null;
return AArch64Address.createAddress(addressingMode, baseReg, offsetReg, immediate, scaled, extendType);
return AArch64Address.createAddress(addressingMode, baseReg, offsetReg, displacement / scaleFactor, isScaled(), extendType);
}
@Override
@ -103,7 +107,7 @@ public final class AArch64AddressValue extends CompositeValue {
AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
AllocatableValue newOffset = (AllocatableValue) proc.doValue(inst, offset, mode, flags);
if (!base.identityEquals(newBase) || !offset.identityEquals(newOffset)) {
return new AArch64AddressValue(getValueKind(), newBase, newOffset, immediate, scaled, addressingMode);
return new AArch64AddressValue(getValueKind(), newBase, newOffset, displacement, scaleFactor, addressingMode);
}
return this;
}

View File

@ -145,7 +145,7 @@ public class AArch64Move {
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
Register dst = asRegister(result);
AArch64Address adr = address.toAddress();
masm.loadAddress(dst, adr, address.getPlatformKind().getSizeInBytes());
masm.loadAddress(dst, adr, address.getScaleFactor());
}
}
@ -241,8 +241,8 @@ public class AArch64Move {
@Override
public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
int immediate = addressValue.getImmediate();
if (state == null && value.equals(addressValue.getBase()) && addressValue.getOffset().equals(Value.ILLEGAL) && immediate >= 0 && immediate < implicitNullCheckLimit) {
int displacement = addressValue.getDisplacement();
if (state == null && value.equals(addressValue.getBase()) && addressValue.getOffset().equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit) {
state = nullCheckState;
return true;
}

View File

@ -84,8 +84,8 @@ public class AArch64Unary {
@Override
public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
int immediate = input.getImmediate();
if (state == null && value.equals(input.getBase()) && input.getOffset().equals(Value.ILLEGAL) && immediate >= 0 && immediate < implicitNullCheckLimit) {
int displacement = input.getDisplacement();
if (state == null && value.equals(input.getBase()) && input.getOffset().equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit) {
state = nullCheckState;
return true;
}

View File

@ -51,6 +51,7 @@ import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
import org.graalvm.compiler.lir.StandardOp.MoveOp;
import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import jdk.vm.ci.code.RegisterValue;
import jdk.vm.ci.code.StackSlot;
@ -414,6 +415,20 @@ public abstract class LIRInstruction {
public void verify() {
}
/**
* Adds a comment to this instruction.
*/
public final void setComment(LIRGenerationResult res, String comment) {
res.setComment(this, comment);
}
/**
* Gets the comment attached to this instruction.
*/
public final String getComment(LIRGenerationResult res) {
return res.getComment(this);
}
public final String toStringWithIdPrefix() {
if (id != -1) {
return String.format("%4d %s", id, toString());
@ -426,6 +441,18 @@ public abstract class LIRInstruction {
return instructionClass.toString(this);
}
public String toString(LIRGenerationResult res) {
String toString = toString();
if (res == null) {
return toString;
}
String comment = getComment(res);
if (comment == null) {
return toString;
}
return String.format("%s // %s", toString, comment);
}
public LIRInstructionClass<?> getLIRInstructionClass() {
return instructionClass;
}

View File

@ -54,19 +54,19 @@ public class SaveCalleeSaveRegisters extends PreAllocationOptimizationPhase {
return;
}
LIR lir = lirGenRes.getLIR();
RegisterMap<Variable> savedRegisters = saveAtEntry(lir, context.lirGen, calleeSaveRegisters, target.arch);
RegisterMap<Variable> savedRegisters = saveAtEntry(lir, context.lirGen, lirGenRes, calleeSaveRegisters, target.arch);
for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
if (block == null) {
continue;
}
if (block.getSuccessorCount() == 0) {
restoreAtExit(lir, context.lirGen.getSpillMoveFactory(), savedRegisters, block);
restoreAtExit(lir, context.lirGen.getSpillMoveFactory(), lirGenRes, savedRegisters, block);
}
}
}
private static RegisterMap<Variable> saveAtEntry(LIR lir, LIRGeneratorTool lirGen, RegisterArray calleeSaveRegisters, Architecture arch) {
private static RegisterMap<Variable> saveAtEntry(LIR lir, LIRGeneratorTool lirGen, LIRGenerationResult lirGenRes, RegisterArray calleeSaveRegisters, Architecture arch) {
AbstractBlockBase<?> startBlock = lir.getControlFlowGraph().getStartBlock();
ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(startBlock);
int insertionIndex = 1;
@ -83,6 +83,7 @@ public class SaveCalleeSaveRegisters extends PreAllocationOptimizationPhase {
Variable saveVariable = lirGen.newVariable(lirKind);
LIRInstruction save = lirGen.getSpillMoveFactory().createMove(saveVariable, registerValue);
buffer.append(insertionIndex, save);
save.setComment(lirGenRes, "SaveCalleeSavedRegisters: saveAtEntry");
saveMap.put(register, saveVariable);
savedRegisterValues[savedRegisterValueIndex++] = registerValue;
}
@ -91,7 +92,7 @@ public class SaveCalleeSaveRegisters extends PreAllocationOptimizationPhase {
return saveMap;
}
private static void restoreAtExit(LIR lir, LIRGeneratorTool.MoveFactory moveFactory, RegisterMap<Variable> calleeSaveRegisters, AbstractBlockBase<?> block) {
private static void restoreAtExit(LIR lir, LIRGeneratorTool.MoveFactory moveFactory, LIRGenerationResult lirGenRes, RegisterMap<Variable> calleeSaveRegisters, AbstractBlockBase<?> block) {
ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
int insertionIndex = instructions.size() - 1;
LIRInsertionBuffer buffer = new LIRInsertionBuffer();
@ -100,6 +101,7 @@ public class SaveCalleeSaveRegisters extends PreAllocationOptimizationPhase {
calleeSaveRegisters.forEach((Register register, Variable saved) -> {
LIRInstruction restore = moveFactory.createMove(register.asValue(saved.getValueKind()), saved);
buffer.append(insertionIndex, restore);
restore.setComment(lirGenRes, "SaveCalleeSavedRegisters: restoreAtExit");
});
buffer.finish();
}

View File

@ -185,10 +185,12 @@ public class LinearScan {
protected final Interval intervalEndMarker;
public final Range rangeEndMarker;
public final boolean detailedAsserts;
private final LIRGenerationResult res;
protected LinearScan(TargetDescription target, LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, AbstractBlockBase<?>[] sortedBlocks,
boolean neverSpillConstants) {
this.ir = res.getLIR();
this.res = res;
this.moveFactory = spillMoveFactory;
this.frameMapBuilder = res.getFrameMapBuilder();
this.sortedBlocks = sortedBlocks;
@ -206,6 +208,10 @@ public class LinearScan {
this.detailedAsserts = DetailedAsserts.getValue(ir.getOptions());
}
public LIRGenerationResult getLIRGenerationResult() {
return res;
}
public Interval intervalEndMarker() {
return intervalEndMarker;
}

View File

@ -75,12 +75,12 @@ public class LinearScanEliminateSpillMovePhase extends LinearScanAllocationPhase
@Override
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
eliminateSpillMoves();
eliminateSpillMoves(lirGenRes);
}
/**
* @return the index of the first instruction that is of interest for
* {@link #eliminateSpillMoves()}
* {@link #eliminateSpillMoves}
*/
protected int firstInstructionOfInterest() {
// skip the first because it is always a label
@ -89,7 +89,7 @@ public class LinearScanEliminateSpillMovePhase extends LinearScanAllocationPhase
// called once before assignment of register numbers
@SuppressWarnings("try")
void eliminateSpillMoves() {
void eliminateSpillMoves(LIRGenerationResult res) {
try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) {
/*
@ -168,6 +168,7 @@ public class LinearScanEliminateSpillMovePhase extends LinearScanAllocationPhase
LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
insertionBuffer.append(j + 1, move);
move.setComment(res, "LSRAEliminateSpillMove: store at definition");
if (Debug.isLogEnabled()) {
Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);

View File

@ -55,16 +55,16 @@ public final class LinearScanOptimizeSpillPositionPhase extends LinearScanAlloca
@Override
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
optimizeSpillPosition();
optimizeSpillPosition(lirGenRes);
allocator.printIntervals("After optimize spill position");
}
@SuppressWarnings("try")
private void optimizeSpillPosition() {
private void optimizeSpillPosition(LIRGenerationResult res) {
try (Indent indent0 = Debug.logAndIndent("OptimizeSpillPositions")) {
LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.getLIR().linearScanOrder().length];
for (Interval interval : allocator.intervals()) {
optimizeInterval(insertionBuffers, interval);
optimizeInterval(insertionBuffers, interval, res);
}
for (LIRInsertionBuffer insertionBuffer : insertionBuffers) {
if (insertionBuffer != null) {
@ -76,7 +76,7 @@ public final class LinearScanOptimizeSpillPositionPhase extends LinearScanAlloca
}
@SuppressWarnings("try")
private void optimizeInterval(LIRInsertionBuffer[] insertionBuffers, Interval interval) {
private void optimizeInterval(LIRInsertionBuffer[] insertionBuffers, Interval interval, LIRGenerationResult res) {
if (interval == null || !interval.isSplitParent() || interval.spillState() != SpillState.SpillInDominator) {
return;
}
@ -165,6 +165,7 @@ public final class LinearScanOptimizeSpillPositionPhase extends LinearScanAlloca
AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location();
AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
move.setComment(res, "LSRAOptimizeSpillPos: optimize spill pos");
Debug.log(Debug.VERBOSE_LEVEL, "Insert spill move %s", move);
move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID);
/*

View File

@ -36,6 +36,7 @@ import org.graalvm.compiler.debug.Indent;
import org.graalvm.compiler.lir.LIRInsertionBuffer;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.LIRValueUtil;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.util.Equivalence;
import org.graalvm.util.EconomicSet;
@ -60,6 +61,8 @@ public class MoveResolver {
private boolean multipleReadsAllowed;
private final int[] registerBlocked;
private final LIRGenerationResult res;
protected void setValueBlocked(Value location, int direction) {
assert direction == 1 || direction == -1 : "out of bounds";
if (isRegister(location)) {
@ -101,7 +104,6 @@ public class MoveResolver {
}
protected MoveResolver(LinearScan allocator) {
this.allocator = allocator;
this.multipleReadsAllowed = false;
this.mappingFrom = new ArrayList<>(8);
@ -110,6 +112,7 @@ public class MoveResolver {
this.insertIdx = -1;
this.insertionBuffer = new LIRInsertionBuffer();
this.registerBlocked = new int[allocator.getRegisters().size()];
this.res = allocator.getLIRGenerationResult();
}
protected boolean checkEmpty() {
@ -265,16 +268,18 @@ public class MoveResolver {
insertIdx = -1;
}
private void insertMove(Interval fromInterval, Interval toInterval) {
private LIRInstruction insertMove(Interval fromInterval, Interval toInterval) {
assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : "move between different types";
assert insertIdx != -1 : "must setup insert position first";
insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
LIRInstruction move = createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location());
insertionBuffer.append(insertIdx, move);
if (Debug.isLogEnabled()) {
Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
}
return move;
}
/**
@ -287,7 +292,7 @@ public class MoveResolver {
return getAllocator().getSpillMoveFactory().createMove(toOpr, fromOpr);
}
private void insertMove(Constant fromOpr, Interval toInterval) {
private LIRInstruction insertMove(Constant fromOpr, Interval toInterval) {
assert insertIdx != -1 : "must setup insert position first";
AllocatableValue toOpr = toInterval.operand;
@ -297,6 +302,7 @@ public class MoveResolver {
if (Debug.isLogEnabled()) {
Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
}
return move;
}
@SuppressWarnings("try")
@ -329,12 +335,14 @@ public class MoveResolver {
if (safeToProcessMove(fromInterval, toInterval)) {
// this interval can be processed because target is free
final LIRInstruction move;
if (fromInterval != null) {
insertMove(fromInterval, toInterval);
move = insertMove(fromInterval, toInterval);
unblockRegisters(fromInterval);
} else {
insertMove(mappingFromOpr.get(i), toInterval);
move = insertMove(mappingFromOpr.get(i), toInterval);
}
move.setComment(res, "MoveResolver resolve mapping");
if (LIRValueUtil.isStackSlotValue(toInterval.location())) {
if (busySpillSlots == null) {
busySpillSlots = new ArrayList<>(2);
@ -404,9 +412,10 @@ public class MoveResolver {
blockRegisters(spillInterval);
// insert a move from register to stack and update the mapping
insertMove(fromInterval, spillInterval);
LIRInstruction move = insertMove(fromInterval, spillInterval);
mappingFrom.set(spillCandidate, spillInterval);
unblockRegisters(fromInterval);
move.setComment(res, "MoveResolver break cycle");
}
@SuppressWarnings("try")

View File

@ -81,6 +81,7 @@ public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhas
private final FrameMapBuilder frameMapBuilder;
private final OptionValues options;
private final RegisterAllocationConfig registerAllocationConfig;
private final LIRGenerationResult res;
private void setValueBlocked(Value location, int direction) {
assert direction == 1 || direction == -1 : "out of bounds";
@ -157,6 +158,7 @@ public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhas
FrameMap frameMap = frameMapBuilderTool.getFrameMap();
this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
this.options = res.getLIR().getOptions();
this.res = res;
}
private boolean checkEmpty() {
@ -314,16 +316,18 @@ public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhas
insertIdx = -1;
}
private void insertMove(Value fromOperand, AllocatableValue toOperand) {
private LIRInstruction insertMove(Value fromOperand, AllocatableValue toOperand) {
assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand;
assert LIRKind.verifyMoveKinds(fromOperand.getValueKind(), fromOperand.getValueKind(), registerAllocationConfig) : "move between different types";
assert insertIdx != -1 : "must setup insert position first";
insertionBuffer.append(insertIdx, createMove(fromOperand, toOperand));
LIRInstruction move = createMove(fromOperand, toOperand);
insertionBuffer.append(insertIdx, move);
if (Debug.isLogEnabled()) {
Debug.log("insert move from %s to %s at %d", fromOperand, toOperand, insertIdx);
}
return move;
}
/**
@ -363,7 +367,8 @@ public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhas
AllocatableValue toLocation = mappingTo.get(i);
if (safeToProcessMove(fromLocation, toLocation)) {
// this interval can be processed because target is free
insertMove(fromLocation, toLocation);
LIRInstruction move = insertMove(fromLocation, toLocation);
move.setComment(res, "TraceGlobalMoveResolver: resolveMapping");
unblock(fromLocation);
if (isStackSlotValue(toLocation)) {
if (busySpillSlots == null) {
@ -422,7 +427,8 @@ public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhas
cycleBreakingSlotsAllocated.increment();
Debug.log("created new slot for spilling: %s", spillSlot);
// insert a move from register to stack and update the mapping
insertMove(from, spillSlot);
LIRInstruction move = insertMove(from, spillSlot);
move.setComment(res, "TraceGlobalMoveResolver: breakCycle");
}
block(spillSlot);
mappingFrom.set(spillCandidate, spillSlot);

View File

@ -308,6 +308,7 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
private void insertSpillMoveBefore(AllocatableValue dst, Value src) {
LIRInstruction move = spillMoveFactory.createMove(dst, src);
insertInstructionsBefore.add(move);
move.setComment(lirGenRes, "BottomUp: spill move before");
Debug.log("insert before %s", move);
}
@ -316,6 +317,7 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
if (!(inst instanceof BlockEndOp)) {
LIRInstruction move = spillMoveFactory.createMove(dst, src);
insertInstructionsAfter.add(move);
move.setComment(lirGenRes, "BottomUp: spill move after");
Debug.log("insert after %s", move);
} else {
Debug.log("Block end op. No from %s to %s necessary.", src, dst);
@ -409,6 +411,7 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
move = spillMoveFactory.createMove(dest, asVariable(phiOut));
}
Debug.log("Inserting load %s", move);
move.setComment(lirGenRes, "BottomUp: phi resolution");
phiResolutionMoves.add(move);
}

View File

@ -65,7 +65,7 @@ final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAlloca
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
boolean shouldEliminateSpillMoves = shouldEliminateSpillMoves(traceBuilderResult, allocator);
eliminateSpillMoves(allocator, shouldEliminateSpillMoves, traceBuilderResult);
eliminateSpillMoves(allocator, shouldEliminateSpillMoves, traceBuilderResult, lirGenRes);
}
private static boolean shouldEliminateSpillMoves(TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
@ -74,7 +74,7 @@ final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAlloca
// called once before assignment of register numbers
@SuppressWarnings("try")
private static void eliminateSpillMoves(TraceLinearScan allocator, boolean shouldEliminateSpillMoves, TraceBuilderResult traceBuilderResult) {
private static void eliminateSpillMoves(TraceLinearScan allocator, boolean shouldEliminateSpillMoves, TraceBuilderResult traceBuilderResult, LIRGenerationResult res) {
try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves: Trace%d", traceBuilderResult.getTraceForBlock(allocator.blockAt(0)).getId())) {
allocator.sortIntervalsBySpillPos();
@ -166,6 +166,7 @@ final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAlloca
LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
insertionBuffer.append(j + 1, move);
move.setComment(res, "TraceLSRAEliminateSpillMove: spill def pos");
if (Debug.isLogEnabled()) {
Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);

View File

@ -24,9 +24,13 @@ package org.graalvm.compiler.lir.gen;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.lir.LIR;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.framemap.FrameMap;
import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.Equivalence;
import jdk.vm.ci.code.CallingConvention;
@ -43,7 +47,12 @@ public class LIRGenerationResult {
/**
* Unique identifier of this compilation.
*/
private final CompilationIdentifier compilationId;
private CompilationIdentifier compilationId;
/**
* Stores comments about a {@link LIRInstruction} , e.g., which phase created it.
*/
private EconomicMap<LIRInstruction, String> comments;
public LIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, CallingConvention callingConvention) {
this.lir = lir;
@ -52,6 +61,28 @@ public class LIRGenerationResult {
this.compilationId = compilationId;
}
/**
* Adds a comment to a {@link LIRInstruction}. Existing comments are replaced.
*/
public final void setComment(LIRInstruction op, String comment) {
if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
if (comments == null) {
comments = EconomicMap.create(Equivalence.IDENTITY);
}
comments.put(op, comment);
}
}
/**
* Gets the comment attached to a {@link LIRInstruction}.
*/
public final String getComment(LIRInstruction op) {
if (comments == null) {
return null;
}
return comments.get(op);
}
/**
* Returns the incoming calling convention for the parameters of the method that is compiled.
*/

View File

@ -190,13 +190,20 @@ public class SimplifyingGraphDecoder extends GraphDecoder {
@Override
protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
Node canonical = canonicalizeFixedNode(node);
Node canonical = canonicalizeFixedNode(methodScope, node);
if (canonical != node) {
handleCanonicalization(loopScope, nodeOrderId, node, canonical);
}
}
private Node canonicalizeFixedNode(FixedNode node) {
/**
* Canonicalizes the provided node, which was originally a {@link FixedNode} but can already be
* canonicalized (and therefore be a non-fixed node).
*
* @param methodScope The current method.
* @param node The node to be canonicalized.
*/
protected Node canonicalizeFixedNode(MethodScope methodScope, Node node) {
if (node instanceof LoadFieldNode) {
LoadFieldNode loadFieldNode = (LoadFieldNode) node;
return loadFieldNode.canonical(canonicalizerTool);

View File

@ -57,7 +57,11 @@ public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtuali
* This constructor exists for node intrinsics that need a stamp based on {@code accessKind}.
*/
public RawLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) {
super(TYPE, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, false);
this(object, offset, accessKind, locationIdentity, false);
}
public RawLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity, boolean forceAnyLocation) {
super(TYPE, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, forceAnyLocation);
}
/**

View File

@ -29,8 +29,4 @@ import org.graalvm.compiler.phases.tiers.HighTierContext;
* Common superclass for phases that perform inlining.
*/
public abstract class AbstractInliningPhase extends BasePhase<HighTierContext> {
@Override
protected boolean isInliningPhase() {
return true;
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Red Hat Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.phases.common;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.extended.JavaReadNode;
import org.graalvm.compiler.nodes.memory.AbstractWriteNode;
import org.graalvm.compiler.nodes.memory.FloatingReadNode;
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.phases.Phase;
/**
* Created by adinn on 09/05/17.
*/
public class AddressLoweringByUsePhase extends Phase {
public abstract static class AddressLoweringByUse {
public abstract AddressNode lower(ValueNode use, Stamp stamp, AddressNode address);
public abstract AddressNode lower(AddressNode address);
}
private final AddressLoweringByUse lowering;
public AddressLoweringByUsePhase(AddressLoweringByUse lowering) {
this.lowering = lowering;
assert lowering != null;
}
@Override
protected void run(StructuredGraph graph) {
// first replace address nodes hanging off known usages
for (Node node : graph.getNodes()) {
AddressNode address;
AddressNode lowered;
if (node instanceof ReadNode) {
ReadNode readNode = (ReadNode) node;
Stamp stamp = readNode.stamp();
address = readNode.getAddress();
lowered = lowering.lower(readNode, stamp, address);
} else if (node instanceof JavaReadNode) {
JavaReadNode javaReadNode = (JavaReadNode) node;
Stamp stamp = javaReadNode.stamp();
address = javaReadNode.getAddress();
lowered = lowering.lower(javaReadNode, stamp, address);
} else if (node instanceof FloatingReadNode) {
FloatingReadNode floatingReadNode = (FloatingReadNode) node;
Stamp stamp = floatingReadNode.stamp();
address = floatingReadNode.getAddress();
lowered = lowering.lower(floatingReadNode, stamp, address);
} else if (node instanceof AbstractWriteNode) {
AbstractWriteNode abstractWriteNode = (AbstractWriteNode) node;
Stamp stamp = abstractWriteNode.value().stamp();
address = abstractWriteNode.getAddress();
lowered = lowering.lower(abstractWriteNode, stamp, address);
// TODO -- PrefetchAllocateNode is not yet implemented for AArch64
// } else if (node instanceof PrefetchAllocateNode) {
// PrefetchAllocateNode prefetchAllocateNode = (PrefetchAllocateNode) node;
// Stamp stamp = prefetchAllocateNode.value().stamp();
// n.b.this getter is not provided!
// address = prefetchAllocateNode.getAddress();
// lowered = lowering.lower(prefetchAllocateNode, stamp, address);
} else {
continue;
}
// the lowered address amy already be a replacement
// in which case we want to use it not delete it!
if (lowered != address) {
address.replaceAtUsages(lowered);
GraphUtil.killWithUnusedFloatingInputs(address);
}
}
// now replace any remaining unlowered address nodes
for (Node node : graph.getNodes()) {
AddressNode lowered;
if (node instanceof RawAddressNode || node instanceof OffsetAddressNode) {
AddressNode address = (AddressNode) node;
lowered = lowering.lower(address);
} else {
continue;
}
// will always be a new AddresNode
node.replaceAtUsages(lowered);
GraphUtil.killWithUnusedFloatingInputs(node);
}
}
}

View File

@ -225,6 +225,11 @@ public class LoweringPhase extends BasePhase<PhaseContext> {
this.loweringStage = loweringStage;
}
@Override
protected boolean shouldDumpBeforeAtBasicLevel() {
return loweringStage == LoweringTool.StandardLoweringStage.HIGH_TIER;
}
/**
* Checks that second lowering of a given graph did not introduce any new nodes.
*

View File

@ -101,6 +101,7 @@ import java.lang.reflect.Constructor;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
@ -408,6 +409,12 @@ public class InliningUtil extends ValueMergeUtil {
*/
@SuppressWarnings("try")
public static EconomicSet<Node> inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) {
return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, null);
}
@SuppressWarnings("try")
public static EconomicSet<Node> inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod,
Consumer<UnmodifiableEconomicMap<Node, Node>> duplicatesConsumer) {
HashSetNodeEventListener listener = new HashSetNodeEventListener();
/*
* This code relies on the fact that Graph.addDuplicates doesn't trigger the
@ -415,7 +422,10 @@ public class InliningUtil extends ValueMergeUtil {
* the graph into the current graph.
*/
try (NodeEventScope nes = invoke.asNode().graph().trackNodeEvents(listener)) {
InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod);
UnmodifiableEconomicMap<Node, Node> duplicates = InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod);
if (duplicatesConsumer != null) {
duplicatesConsumer.accept(duplicates);
}
}
return listener.getNodes();
}

View File

@ -277,7 +277,7 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
// do the actual inlining for every invoke
for (int i = 0; i < numberOfMethods; i++) {
Invoke invokeForInlining = (Invoke) successors[i].next();
canonicalizeNodes.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), false));
canonicalizeNodes.addAll(doInline(i, invokeForInlining));
}
if (returnValuePhi != null) {
canonicalizeNodes.add(returnValuePhi);
@ -285,6 +285,10 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
return canonicalizeNodes;
}
protected EconomicSet<Node> doInline(int index, Invoke invokeForInlining) {
return inline(invokeForInlining, methodAt(index), inlineableElementAt(index), false);
}
private int getTypeCount(int concreteMethodIndex) {
int count = 0;
for (int i = 0; i < typesToConcretes.size(); i++) {

View File

@ -150,8 +150,12 @@ public abstract class BasePhase<C> implements PhaseSizeContract {
}
private boolean dumpBefore(final StructuredGraph graph, final C context, boolean isTopLevel) {
if (isTopLevel && Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
Debug.dump(Debug.VERBOSE_LEVEL, graph, "Before phase %s", getName());
if (isTopLevel && (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL) || shouldDumpBeforeAtBasicLevel() && Debug.isDumpEnabled(Debug.BASIC_LEVEL))) {
if (shouldDumpBeforeAtBasicLevel()) {
Debug.dump(Debug.BASIC_LEVEL, graph, "Before phase %s", getName());
} else {
Debug.dump(Debug.VERBOSE_LEVEL, graph, "Before phase %s", getName());
}
} else if (!isTopLevel && Debug.isDumpEnabled(Debug.VERBOSE_LEVEL + 1)) {
Debug.dump(Debug.VERBOSE_LEVEL + 1, graph, "Before subphase %s", getName());
} else if (Debug.isDumpEnabled(Debug.ENABLED_LEVEL) && shouldDump(graph, context)) {
@ -161,7 +165,11 @@ public abstract class BasePhase<C> implements PhaseSizeContract {
return false;
}
protected boolean isInliningPhase() {
protected boolean shouldDumpBeforeAtBasicLevel() {
return false;
}
protected boolean shouldDumpAfterAtBasicLevel() {
return false;
}
@ -207,7 +215,7 @@ public abstract class BasePhase<C> implements PhaseSizeContract {
private void dumpAfter(final StructuredGraph graph, boolean isTopLevel, boolean dumpedBefore) {
boolean dumped = false;
if (isTopLevel) {
if (isInliningPhase()) {
if (shouldDumpAfterAtBasicLevel()) {
if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
Debug.dump(Debug.BASIC_LEVEL, graph, "After phase %s", getName());
dumped = true;

View File

@ -150,6 +150,7 @@ public class VerifyDebugUsage extends VerifyPhase<PhaseContext> {
*/
private static final Set<String> BasicLevelStructuredGraphDumpWhitelist = new HashSet<>(Arrays.asList(
"org.graalvm.compiler.phases.BasePhase.dumpAfter",
"org.graalvm.compiler.phases.BasePhase.dumpBefore",
"org.graalvm.compiler.core.GraalCompiler.emitFrontEnd",
"org.graalvm.compiler.truffle.PartialEvaluator.fastPartialEvaluation",
"org.graalvm.compiler.truffle.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings",

View File

@ -175,7 +175,7 @@ public class BinaryGraphPrinter implements GraphPrinter {
@Override
public void print(Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException {
writeByte(BEGIN_GRAPH);
if (CURRENT_MAJOR_VERSION == 3) {
if (CURRENT_MAJOR_VERSION >= 3) {
writeInt(id);
writeString(format);
writeInt(args.length);
@ -183,7 +183,7 @@ public class BinaryGraphPrinter implements GraphPrinter {
writePropertyObject(a);
}
} else {
writePoolObject(String.format(format, args));
writePoolObject(formatTitle(id, format, args));
}
writeGraph(graph, properties);
flush();
@ -386,12 +386,14 @@ public class BinaryGraphPrinter implements GraphPrinter {
} else if (object instanceof NodeClass) {
NodeClass<?> nodeClass = (NodeClass<?>) object;
writeByte(POOL_NODE_CLASS);
if (CURRENT_MAJOR_VERSION == 3) {
if (CURRENT_MAJOR_VERSION >= 3) {
writePoolObject(nodeClass.getJavaClass());
writeString(nodeClass.getNameTemplate());
} else {
writeString(nodeClass.getJavaClass().getSimpleName());
String nameTemplate = nodeClass.getNameTemplate();
writeString(nameTemplate.isEmpty() ? nodeClass.shortName() : nameTemplate);
}
writeString(nodeClass.getNameTemplate());
writeEdgesInfo(nodeClass, Inputs);
writeEdgesInfo(nodeClass, Successors);
} else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) {

View File

@ -50,6 +50,7 @@ import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
import org.graalvm.compiler.lir.debug.IntervalDumper;
import org.graalvm.compiler.lir.debug.IntervalDumper.IntervalVisitor;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractEndNode;
@ -85,6 +86,7 @@ class CFGPrinter extends CompilationPrinter {
protected ScheduleResult schedule;
protected ResolvedJavaMethod method;
protected GlobalLivenessInfo livenessInfo;
protected LIRGenerationResult res;
/**
* Creates a control flow graph printer.
@ -555,7 +557,7 @@ class CFGPrinter extends CompilationPrinter {
out.adjustIndentation(level);
}
out.print(" instruction ").print(inst.toString()).print(COLUMN_END);
out.print(" instruction ").print(inst.toString(res)).print(COLUMN_END);
out.println(COLUMN_END);
}
}

View File

@ -51,6 +51,7 @@ import org.graalvm.compiler.java.BciBlockMapping;
import org.graalvm.compiler.lir.LIR;
import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
import org.graalvm.compiler.lir.debug.IntervalDumper;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
@ -173,6 +174,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
}
cfgPrinter.nodeLirGenerator = Debug.contextLookup(NodeLIRBuilder.class);
cfgPrinter.livenessInfo = Debug.contextLookup(GlobalLivenessInfo.class);
cfgPrinter.res = Debug.contextLookup(LIRGenerationResult.class);
if (cfgPrinter.nodeLirGenerator != null) {
cfgPrinter.target = cfgPrinter.nodeLirGenerator.getLIRGeneratorTool().target();
}
@ -238,6 +240,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
} finally {
cfgPrinter.target = null;
cfgPrinter.lir = null;
cfgPrinter.res = null;
cfgPrinter.nodeLirGenerator = null;
cfgPrinter.livenessInfo = null;
cfgPrinter.cfg = null;

View File

@ -267,7 +267,7 @@ public class CanonicalStringGraphPrinter implements GraphPrinter {
TTY.println("Dumping string graphs in %s", this.root);
this.root = null;
}
String title = id + ": " + String.format(format, args);
String title = formatTitle(id, format, args);
Path filePath = currentDirectory.resolve(escapeFileName(title));
try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filePath.toFile())))) {
switch (PrintCanonicalGraphStringFlavor.getValue(options)) {

View File

@ -36,6 +36,7 @@ import org.graalvm.compiler.serviceprovider.JDK9Method;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaUtil;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.runtime.JVMCI;
@ -141,6 +142,22 @@ interface GraphPrinter extends Closeable {
}
}
default String formatTitle(int id, String format, Object... args) {
/*
* If an argument is a Class, replace it with the simple name.
*/
Object[] newArgs = new Object[args.length];
for (int i = 0; i < newArgs.length; i++) {
Object arg = args[i];
if (arg instanceof JavaType) {
newArgs[i] = ((JavaType) arg).getUnqualifiedName();
} else {
newArgs[i] = arg;
}
}
return id + ": " + String.format(format, newArgs);
}
static String truncate(String s) {
if (s.length() > MAX_CONSTANT_TO_STRING_LENGTH) {
return s.substring(0, MAX_CONSTANT_TO_STRING_LENGTH - 3) + "...";

View File

@ -115,7 +115,7 @@ public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPr
*/
@Override
public void print(Graph graph, Map<Object, Object> properties, int id, String format, Object... args) {
String title = id + ": " + String.format(format, args);
String title = formatTitle(id, format, args);
beginGraph(title);
EconomicSet<Node> noBlockNodes = EconomicSet.create(Equivalence.IDENTITY);
ScheduleResult schedule = null;

View File

@ -68,6 +68,7 @@ public class ReplacementsParseTest extends ReplacementsTest {
private static final String IN_INTERPRETED_HANDLER_MARKER = "*** in interpreted handler ***";
private InlineInvokePlugin.InlineInfo inlineInvokeDecision;
private String inlineInvokeMethodName = null;
@SuppressWarnings("serial")
static class CustomError extends Error {
@ -351,12 +352,15 @@ public class ReplacementsParseTest extends ReplacementsTest {
test(options, "callStringize", Boolean.TRUE);
String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER;
String compiledReturnValue = IN_COMPILED_HANDLER_MARKER;
for (int i = 0; i < 1000; i++) {
// Ensures 'exception seen' bit is set for call to stringize
callStringize(THROW_EXCEPTION_MARKER);
}
forceCompileOverride = true;
testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringize", THROW_EXCEPTION_MARKER);
inlineInvokeDecision = InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
inlineInvokeMethodName = "stringizeId";
try {
testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringize", THROW_EXCEPTION_MARKER);
} finally {
inlineInvokeDecision = null;
inlineInvokeMethodName = null;
}
}
@Test
@ -378,14 +382,17 @@ public class ReplacementsParseTest extends ReplacementsTest {
test(options, "callStringizeId", new TestObject("a string"));
test(options, "callStringizeId", new TestObject(Boolean.TRUE));
TestObject exceptionTestObject = new TestObject(THROW_EXCEPTION_MARKER);
for (int i = 0; i < 1000; i++) {
// Ensures 'exception seen' bit is set for call to stringizeId
callStringizeId(exceptionTestObject);
}
String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER;
String compiledReturnValue = IN_COMPILED_HANDLER_MARKER;
forceCompileOverride = true;
testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringizeId", exceptionTestObject);
inlineInvokeDecision = InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
inlineInvokeMethodName = "stringizeId";
try {
testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringizeId", exceptionTestObject);
} finally {
inlineInvokeDecision = null;
inlineInvokeMethodName = null;
}
}
public static Object callStringize(Object obj) {
@ -474,7 +481,10 @@ public class ReplacementsParseTest extends ReplacementsTest {
@Override
protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
return inlineInvokeDecision;
if (inlineInvokeMethodName == null || inlineInvokeMethodName.equals(method.getName())) {
return inlineInvokeDecision;
}
return null;
}
@Test

View File

@ -94,6 +94,7 @@ import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
import org.graalvm.compiler.nodes.java.StoreFieldNode;
import org.graalvm.compiler.nodes.java.StoreIndexedNode;
import org.graalvm.compiler.nodes.spi.StampProvider;
import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
@ -375,56 +376,6 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
}
}
/**
* A graph builder context that allows appending one node to the graph. If a node is appended,
* the target fixed node is replaced with the new node, and clients must afterwards call commit
* to complete the replacement.
*
* This graph builder context is intended to be used with the {@link NodePlugin} objects passed
* to the graph decoder.
*/
protected class PEOnDemandAppendGraphBuilderContext extends PEAppendGraphBuilderContext {
private final FixedNode targetNode;
private FixedWithNextNode predecessor;
public PEOnDemandAppendGraphBuilderContext(PEMethodScope inlineScope, FixedNode targetNode) {
super(inlineScope, targetNode.predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) targetNode.predecessor() : null);
this.targetNode = targetNode;
this.predecessor = targetNode.predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) targetNode.predecessor() : null;
}
@Override
public void push(JavaKind kind, ValueNode value) {
super.push(kind, value);
}
private void checkPopLastInstruction() {
if (predecessor != null) {
targetNode.replaceAtPredecessor(null);
lastInstr = predecessor;
predecessor = null;
}
}
@Override
public <T extends ValueNode> T append(T v) {
checkPopLastInstruction();
return super.append(v);
}
public FixedNode commit(LoopScope loopScope, int nodeOrderId, FixedWithNextNode oldAsFixedWithNextNode) {
registerNode(loopScope, nodeOrderId, pushedNode, true, false);
targetNode.replaceAtUsages(pushedNode);
if (oldAsFixedWithNextNode != null) {
FixedNode successor = oldAsFixedWithNextNode.next();
successor.replaceAtPredecessor(null);
lastInstr.setNext(successor);
deleteFixedNode(targetNode);
}
return lastInstr;
}
}
@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
static class ExceptionPlaceholderNode extends ValueNode {
public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
@ -737,6 +688,26 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
PEMethodScope inlineScope = new PEMethodScope(graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1,
loopExplosionPlugin, arguments);
if (!inlineMethod.isStatic()) {
if (StampTool.isPointerAlwaysNull(arguments[0])) {
/*
* The receiver is null, so we can unconditionally throw a NullPointerException
* instead of performing any inlining.
*/
DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException));
predecessor.setNext(deoptimizeNode);
finishInlining(inlineScope);
/* Continue decoding in the caller. */
return loopScope;
} else if (!StampTool.isPointerNonNull(arguments[0])) {
/* The receiver might be null, so we need to insert a null check. */
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, predecessor);
arguments[0] = graphBuilderContext.nullCheckedValue(arguments[0]);
predecessor = graphBuilderContext.lastInstr;
}
}
/*
* Do the actual inlining by returning the initial loop scope for the inlined method scope.
*/
@ -926,26 +897,35 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider);
@SuppressWarnings("try")
@Override
protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
PEMethodScope methodScope = (PEMethodScope) s;
FixedNode replacedNode = node;
if (node instanceof ForeignCallNode) {
ForeignCallNode foreignCall = (ForeignCallNode) node;
if (foreignCall.getBci() == BytecodeFrame.UNKNOWN_BCI && methodScope.invokeData != null) {
foreignCall.setBci(methodScope.invokeData.invoke.bci());
}
} else if (nodePlugins != null && nodePlugins.length > 0) {
}
super.handleFixedNode(methodScope, loopScope, nodeOrderId, node);
}
@SuppressWarnings("try")
@Override
protected Node canonicalizeFixedNode(MethodScope s, Node node) {
PEMethodScope methodScope = (PEMethodScope) s;
Node replacedNode = node;
if (nodePlugins != null && nodePlugins.length > 0) {
if (node instanceof LoadFieldNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
LoadFieldNode loadFieldNode = (LoadFieldNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, loadFieldNode);
ResolvedJavaField field = loadFieldNode.field();
if (loadFieldNode.isStatic()) {
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleLoadStaticField(graphBuilderContext, field)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, loadFieldNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
@ -953,20 +933,20 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
ValueNode object = loadFieldNode.object();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleLoadField(graphBuilderContext, object, field)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, loadFieldNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
}
} else if (node instanceof StoreFieldNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
StoreFieldNode storeFieldNode = (StoreFieldNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, storeFieldNode);
ResolvedJavaField field = storeFieldNode.field();
if (storeFieldNode.isStatic()) {
ValueNode value = storeFieldNode.value();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleStoreStaticField(graphBuilderContext, field, value)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, storeFieldNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
@ -975,93 +955,70 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
ValueNode value = storeFieldNode.value();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleStoreField(graphBuilderContext, object, field, value)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, storeFieldNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
}
} else if (node instanceof LoadIndexedNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, loadIndexedNode);
ValueNode array = loadIndexedNode.array();
ValueNode index = loadIndexedNode.index();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleLoadIndexed(graphBuilderContext, array, index, loadIndexedNode.elementKind())) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, loadIndexedNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
} else if (node instanceof StoreIndexedNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
StoreIndexedNode storeIndexedNode = (StoreIndexedNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, storeIndexedNode);
ValueNode array = storeIndexedNode.array();
ValueNode index = storeIndexedNode.index();
ValueNode value = storeIndexedNode.value();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleStoreIndexed(graphBuilderContext, array, index, storeIndexedNode.elementKind(), value)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, storeIndexedNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
} else if (node instanceof NewInstanceNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
NewInstanceNode newInstanceNode = (NewInstanceNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, newInstanceNode);
ResolvedJavaType type = newInstanceNode.instanceClass();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleNewInstance(graphBuilderContext, type)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, newInstanceNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
} else if (node instanceof NewArrayNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
NewArrayNode newArrayNode = (NewArrayNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, newArrayNode);
ResolvedJavaType elementType = newArrayNode.elementType();
ValueNode length = newArrayNode.length();
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleNewArray(graphBuilderContext, elementType, length)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, newArrayNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
} else if (node instanceof NewMultiArrayNode) {
PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
NewMultiArrayNode newArrayNode = (NewMultiArrayNode) node;
PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, newArrayNode);
ResolvedJavaType elementType = newArrayNode.type();
ValueNode[] dimensions = newArrayNode.dimensions().toArray(new ValueNode[0]);
for (NodePlugin nodePlugin : nodePlugins) {
if (nodePlugin.handleNewMultiArray(graphBuilderContext, elementType, dimensions)) {
replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, newArrayNode);
replacedNode = graphBuilderContext.pushedNode;
break;
}
}
}
}
NodeSourcePosition pos = replacedNode.getNodeSourcePosition();
if (pos != null && methodScope.isInlinedMethod()) {
NodeSourcePosition newPosition = pos.addCaller(methodScope.getCallerBytecodePosition());
try (DebugCloseable scope = replacedNode.graph().withNodeSourcePosition(newPosition)) {
super.handleFixedNode(s, loopScope, nodeOrderId, replacedNode);
}
if (replacedNode.isAlive()) {
replacedNode.setNodeSourcePosition(newPosition);
}
} else {
super.handleFixedNode(s, loopScope, nodeOrderId, replacedNode);
}
}
private static void deleteFixedNode(FixedNode node) {
FrameState frameState = null;
if (node instanceof StateSplit) {
frameState = ((StateSplit) node).stateAfter();
}
node.safeDelete();
if (frameState != null && frameState.hasNoUsages()) {
frameState.safeDelete();
}
return super.canonicalizeFixedNode(methodScope, replacedNode);
}
@Override

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.options;
/**
* Classifies options in several categories depending on who this option is relevant for.
*
* @since 1.0
*/
public enum OptionCategory {
/**
* An option common for users to apply.
*
* @since 1.0
*/
USER,
/**
* An option only relevant in corner cases and for fine-tuning.
*
* @since 1.0
*/
EXPERT,
/**
* An option only relevant when debugging language or instrument implementations.
*
* @since 1.0
*/
DEBUG
}

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.options;
/**
* Represents meta-data for a single option.
*
* @since 1.0
*/
public final class OptionDescriptor {
private final OptionKey<?> key;
private final String name;
private final String help;
private final OptionCategory kind;
private final boolean deprecated;
OptionDescriptor(OptionKey<?> key, String name, String help, OptionCategory kind, boolean deprecated) {
this.key = key;
this.name = name;
this.help = help;
this.kind = kind;
this.deprecated = deprecated;
}
/**
* Returns the option name of the option represented by this descriptor.
*
* @since 1.0
*/
public String getName() {
return name;
}
/**
* Returns the key for this option.
*
* @since 1.0
*/
public OptionKey<?> getKey() {
return key;
}
/**
* Returns <code>true</code> if this option was marked deprecated. This indicates that the
* option is going to be removed in a future release or its use is not recommended.
*
* @since 1.0
*/
public boolean isDeprecated() {
return deprecated;
}
/**
* Returns the user category of this option.
*
* @since 1.0
*/
public OptionCategory getCategory() {
return kind;
}
/**
* Returns a human-readable description on how to use the option.
*
* @since 1.0
*/
public String getHelp() {
return help;
}
/**
* @since 1.0
*/
@Override
public String toString() {
return "OptionDescriptor [key=" + key + ", help=" + help + ", kind=" + kind + ", deprecated=" + deprecated + "]";
}
/**
* Creates a new option descriptor builder by key. The option group and name is inferred by the
* key.
*
* @since 1.0
*/
public static <T> Builder newBuilder(OptionKey<T> key, String name) {
return new Builder(key, name);
}
/**
* Represents an option descriptor builder.
*
* @since 1.0
*/
public static final class Builder {
private final OptionKey<?> key;
private final String name;
private boolean deprecated;
private OptionCategory category;
private String help;
Builder(OptionKey<?> key, String name) {
this.key = key;
this.name = name;
}
/**
* Defines the user category for this option. The default value is
* {@link OptionCategory#DEBUG}.
*
* @since 1.0
*/
public Builder category(@SuppressWarnings("hiding") OptionCategory category) {
this.category = category;
return this;
}
/**
* Defines whether this option is deprecated. The default value for deprecated is
* <code>false</code>. This can be used to evolve options between releases.
*
* @since 1.0
*/
public Builder deprecated(@SuppressWarnings("hiding") boolean deprecated) {
this.deprecated = deprecated;
return this;
}
/**
* Specifies a human-readable description on how to use the option.
*
* @since 1.0
*/
public Builder help(@SuppressWarnings("hiding") String help) {
this.help = help;
return this;
}
/**
* Builds and returns a new option descriptor.
*
* @since 1.0
*/
public OptionDescriptor build() {
return new OptionDescriptor(key, name, help, category, deprecated);
}
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.options;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An interface to a set of {@link OptionDescriptor}s.
*
* @since 1.0
*/
public interface OptionDescriptors extends Iterable<OptionDescriptor> {
/**
* An empty set of option descriptors.
*
* @since 1.0
*/
OptionDescriptors EMPTY = new OptionDescriptors() {
public Iterator<OptionDescriptor> iterator() {
return Collections.<OptionDescriptor> emptyList().iterator();
}
public OptionDescriptor get(String key) {
return null;
}
};
/**
* Gets the {@link OptionDescriptor} matching a given option name or {@code null} if this option
* descriptor set doesn't contain a matching option name.
*
* @since 1.0
*/
OptionDescriptor get(String optionName);
/**
* Create a union options descriptor out of multiple given descriptors. The operation
* descriptors are not checked for duplicate keys. The option descriptors are iterated in
* declaration order.
*
* @since 1.0
*/
static OptionDescriptors createUnion(OptionDescriptors... descriptors) {
if (descriptors.length == 0) {
return EMPTY;
} else if (descriptors.length == 1) {
return descriptors[0];
} else {
return new UnionOptionDescriptors(descriptors);
}
}
}
final class UnionOptionDescriptors implements OptionDescriptors {
final OptionDescriptors[] descriptorsList;
UnionOptionDescriptors(OptionDescriptors[] descriptors) {
// defensive copy
this.descriptorsList = Arrays.copyOf(descriptors, descriptors.length);
}
public Iterator<OptionDescriptor> iterator() {
return new Iterator<OptionDescriptor>() {
Iterator<OptionDescriptor> descriptors = descriptorsList[0].iterator();
int descriptorsIndex = 0;
OptionDescriptor next = null;
public boolean hasNext() {
return fetchNext() != null;
}
private OptionDescriptor fetchNext() {
if (next != null) {
return next;
}
if (descriptors.hasNext()) {
next = descriptors.next();
return next;
} else if (descriptorsIndex < descriptorsList.length - 1) {
descriptorsIndex++;
descriptors = descriptorsList[descriptorsIndex].iterator();
return fetchNext();
} else {
return null;
}
}
public OptionDescriptor next() {
OptionDescriptor fetchedNext = fetchNext();
if (fetchedNext != null) {
// consume next
this.next = null;
return fetchedNext;
} else {
throw new NoSuchElementException();
}
}
};
}
public OptionDescriptor get(String value) {
for (OptionDescriptors descriptors : descriptorsList) {
OptionDescriptor descriptor = descriptors.get(value);
if (descriptor != null) {
return descriptor;
}
}
return null;
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.options;
import java.util.Objects;
/**
* Represents the option key for a option specification.
*
* @since 1.0
*/
public final class OptionKey<T> {
private final OptionType<T> type;
private final T defaultValue;
/**
* Constructs a new option key given a default value. Throws {@link IllegalArgumentException} if
* no default {@link OptionType} could be {@link OptionType#defaultType(Object) resolved} for
* the given type. The default value must not be <code>null</code>.
*
* @since 1.0
*/
public OptionKey(T defaultValue) {
Objects.requireNonNull(defaultValue);
this.defaultValue = defaultValue;
this.type = OptionType.defaultType(defaultValue);
if (type == null) {
throw new IllegalArgumentException("No default type specified for type " + defaultValue.getClass().getName() + ". Specify the option type explicitely to resolve this.");
}
}
/**
* Contructs a new option key givena default value and option key. The default value and the
* type must not be <code>null</code>.
*
* @since 1.0
*/
public OptionKey(T defaultValue, OptionType<T> type) {
Objects.requireNonNull(defaultValue);
Objects.requireNonNull(type);
this.defaultValue = defaultValue;
this.type = type;
}
/**
* Returns the option type of this key.
*
* @since 1.0
*/
public OptionType<T> getType() {
return type;
}
/**
* Returns the default value for this option.
*
* @since 1.0
*/
public T getDefaultValue() {
return defaultValue;
}
/**
* Returns the value of this key given the {@link OptionValues values}.
*
* @since 1.0
*/
public T getValue(OptionValues values) {
return values.get(this);
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.options;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Represents a type of an option that allows to convert string values to a java value.
*
* @since 1.0
*/
public final class OptionType<T> {
private final String name;
private final Function<String, T> stringConverter;
private final Consumer<T> validator;
private final T defaultValue;
/**
* Constructs a new option type with name, defaultValue and function that allows to convert a
* string to the option type.
*
* @param name the name of the type to identify it
* @param defaultValue the default value to use if no value is given
* @param stringConverter a function that converts a string value to the actual option value.
* Can throw {@link IllegalArgumentException} to indicate an invalid string.
* @param validator used for validating the option value. Throws
* {@link IllegalArgumentException} if the value is invalid.
*
* @since 1.0
*/
public OptionType(String name, T defaultValue, Function<String, T> stringConverter, Consumer<T> validator) {
Objects.requireNonNull(name);
Objects.requireNonNull(defaultValue);
Objects.requireNonNull(stringConverter);
Objects.requireNonNull(validator);
this.name = name;
this.stringConverter = stringConverter;
this.defaultValue = defaultValue;
this.validator = validator;
}
/**
* Constructs a new option type with name, defaultValue and function that allows to convert a
* string to the option type.
*
* @param name the name of the type to identify it
* @param defaultValue the default value to use if no value is given
* @param stringConverter a function that converts a string value to the actual option value.
* Can throw {@link IllegalArgumentException} to indicate an invalid string.
*
* @since 1.0
*/
public OptionType(String name, T defaultValue, Function<String, T> stringConverter) {
this(name, defaultValue, stringConverter, new Consumer<T>() {
public void accept(T t) {
}
});
}
/**
* Returns the default value of this type, to be used if no value is available.
*
* @since 1.0
*/
public T getDefaultValue() {
return defaultValue;
}
/**
* Returns the name of this type.
*
* @since 1.0
*/
public String getName() {
return name;
}
/**
* Converts a string value, validates it and converts it to an object of this type.
*
* @throws IllegalArgumentException if the value is invalid or cannot be converted.
* @since 1.0
*/
public T convert(String value) {
T v = stringConverter.apply(value);
validate(v);
return v;
}
/**
* Validates an option value and throws an {@link IllegalArgumentException} if it is invalid.
*
* @throws IllegalArgumentException if the value is invalid or cannot be converted.
* @since 1.0
*/
public void validate(T value) {
validator.accept(value);
}
/**
* @since 1.0
*/
@Override
public String toString() {
return "OptionType[name=" + name + ", defaultValue=" + defaultValue + "]";
}
private static Map<Class<?>, OptionType<?>> DEFAULTTYPES = new HashMap<>();
static {
DEFAULTTYPES.put(Boolean.class, new OptionType<>("Boolean", false, new Function<String, Boolean>() {
public Boolean apply(String t) {
if ("true".equals(t)) {
return Boolean.TRUE;
} else if ("false".equals(t)) {
return Boolean.FALSE;
} else {
throw new IllegalArgumentException(String.format("Invalid boolean option value '%s'. The value of the option must be '%s' or '%s'.", t, "true", "false"));
}
}
}));
DEFAULTTYPES.put(Byte.class, new OptionType<>("Byte", (byte) 0, new Function<String, Byte>() {
public Byte apply(String t) {
try {
return Byte.parseByte(t);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}));
DEFAULTTYPES.put(Integer.class, new OptionType<>("Integer", 0, new Function<String, Integer>() {
public Integer apply(String t) {
try {
return Integer.parseInt(t);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}));
DEFAULTTYPES.put(Long.class, new OptionType<>("Long", 0L, new Function<String, Long>() {
public Long apply(String t) {
try {
return Long.parseLong(t);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}));
DEFAULTTYPES.put(Float.class, new OptionType<>("Float", 0.0f, new Function<String, Float>() {
public Float apply(String t) {
try {
return Float.parseFloat(t);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}));
DEFAULTTYPES.put(Double.class, new OptionType<>("Double", 0.0d, new Function<String, Double>() {
public Double apply(String t) {
try {
return Double.parseDouble(t);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}));
DEFAULTTYPES.put(String.class, new OptionType<>("String", "0", new Function<String, String>() {
public String apply(String t) {
return t;
}
}));
}
/**
* Returns the default option type for a given value. Returns <code>null</code> if no default
* option type is available for this java type.
*
* @since 1.0
*/
@SuppressWarnings("unchecked")
public static <T> OptionType<T> defaultType(Object value) {
return (OptionType<T>) DEFAULTTYPES.get(value.getClass());
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.options;
/**
* Represents a set of option values based on an {@link OptionDescriptor}.
*
* @since 1.0
*/
public interface OptionValues {
/**
* Returns all available options.
*
* @since 1.0
*/
OptionDescriptors getDescriptors();
/**
* Sets the value of {@code optionKey} to {@code value}.
*
* @since 1.0
*/
<T> void set(OptionKey<T> optionKey, T value);
/**
* Returns the value of a given option. Returns <code>null</code> if the option does not exist.
*
* @since 1.0
*/
<T> T get(OptionKey<T> optionKey);
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* The Graal-SDK options package contains reusable collection classes for options.
*
* @see org.graalvm.options.OptionDescriptor
* @see org.graalvm.options.OptionValues
*
* @since 1.0
*/
package org.graalvm.options;