Merge
This commit is contained in:
commit
1cbd0bd202
@ -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"],
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -110,5 +110,4 @@ public class ResolveConstantStubCall extends DeoptimizingStubCall implements Can
|
||||
}
|
||||
gen.setResult(this, result);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
/*
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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) + "...";
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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;
|
Loading…
x
Reference in New Issue
Block a user