Skip to content

Commit

Permalink
Initial SVM Windows PE/Coff Support
Browse files Browse the repository at this point in the history
  • Loading branch information
bobvandette committed May 4, 2018
1 parent 5c44ef8 commit 147683e
Show file tree
Hide file tree
Showing 41 changed files with 2,859 additions and 69 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*.jar
*.log
*.o
*.obj
*.orig
*.pdf
*.pyc
Expand Down
14 changes: 9 additions & 5 deletions compiler/mx.compiler/mx_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def add_jvmci_classpath_entry(entry):
"""
_jvmci_classpath.append(entry)

if jdk.javaCompliance != '9' and jdk.javaCompliance != '10':
if jdk.javaCompliance != '9' and jdk.javaCompliance != '10' and mx.get_os() != 'windows':
# The jdk.internal.vm.compiler.management module is
# not available in 9 nor upgradeable in 10
add_jvmci_classpath_entry(JVMCIClasspathEntry('GRAAL_MANAGEMENT'))
Expand Down Expand Up @@ -514,7 +514,7 @@ def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVM
with Task('MakeGraalJDK', tasks, tags=GraalTags.test) as t:
if t and isJDK8:
try:
makegraaljdk(['-a', 'graaljdk.tar', 'graaljdk'])
makegraaljdk(['-a', 'graaljdk.tar', '-b', 'graaljdk'])
finally:
if exists('graaljdk'):
shutil.rmtree('graaljdk')
Expand Down Expand Up @@ -1045,6 +1045,7 @@ def makegraaljdk(args):
parser = ArgumentParser(prog='mx makegraaljdk')
parser.add_argument('-f', '--force', action='store_true', help='overwrite existing GraalJDK')
parser.add_argument('-a', '--archive', action='store', help='name of archive to create', metavar='<path>')
parser.add_argument('-b', '--bootstrap', action='store_true', help='execute a bootstrap of the created GraalJDK')
parser.add_argument('dest', help='destination directory for GraalJDK', metavar='<path>')
args = parser.parse_args(args)
if isJDK8:
Expand All @@ -1063,8 +1064,10 @@ def makegraaljdk(args):
jvmciDir = join(dstJdk, 'jre', 'lib', 'jvmci')
assert exists(jvmciDir), jvmciDir + ' does not exist'

if mx.get_os() == 'darwin' or mx.get_os() == 'windows':
if mx.get_os() == 'darwin':
jvmlibDir = join(dstJdk, 'jre', 'lib', 'server')
if mx.get_os() == 'windows':
jvmlibDir = join(dstJdk, 'jre', 'bin', 'server')
else:
jvmlibDir = join(dstJdk, 'jre', 'lib', mx.get_arch(), 'server')
jvmlib = join(jvmlibDir, mx.add_lib_prefix(mx.add_lib_suffix('jvm')))
Expand Down Expand Up @@ -1121,8 +1124,9 @@ def makegraaljdk(args):
mx.abort('Could not find "{}" in output of `java -version`:\n{}'.format(pattern.pattern, os.linesep.join(out.lines)))

exe = join(dstJdk, 'bin', mx.exe_suffix('java'))
with StdoutUnstripping(args=[], out=None, err=None, mapFiles=mapFiles) as u:
mx.run([exe, '-XX:+BootstrapJVMCI', '-version'], out=u.out, err=u.err)
if args.bootstrap:
with StdoutUnstripping(args=[], out=None, err=None, mapFiles=mapFiles) as u:
mx.run([exe, '-XX:+BootstrapJVMCI', '-version'], out=u.out, err=u.err)
if args.archive:
mx.log('Archiving {}'.format(args.archive))
create_archive(dstJdk, args.archive, basename(args.dest) + '/')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2018, 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.core.test;

import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.IfNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
import org.graalvm.compiler.nodes.calc.ReinterpretNode;
import org.junit.Assert;
import org.junit.Test;

/**
* Tests that substitutions for {@link Double#doubleToLongBits(double)} and
* {@link Float#floatToIntBits(float)} produce graphs such that multiple calls to these methods with
* the same input are canonicalized.
*/
public class CanonicalizedConversionTest extends GraalCompilerTest {

@Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
int reinterpretCount = 0;
int floatEqualsCount = 0;
int addCount = 0;
for (Node node : graph.getNodes()) {
if (node instanceof ReinterpretNode) {
reinterpretCount++;
} else if (node instanceof FloatEqualsNode) {
floatEqualsCount++;
} else if (node instanceof IfNode) {
Assert.fail("Unexpected node: " + node);
} else if (node instanceof AddNode) {
addCount++;
}
}
Assert.assertEquals(1, reinterpretCount);
Assert.assertEquals(1, floatEqualsCount);
Assert.assertEquals(2, addCount);
return true;
}

@Test
public void test4() {
test("snippet4", 567.890F);
test("snippet4", -567.890F);
test("snippet4", Float.NaN);
}

public static int snippet4(float value) {
return Float.floatToIntBits(value) + Float.floatToIntBits(value) + Float.floatToIntBits(value);
}

@Test
public void test5() {
test("snippet5", 567.890D);
test("snippet5", -567.890D);
test("snippet5", Double.NaN);
}

public static long snippet5(double value) {
return Double.doubleToLongBits(value) + Double.doubleToLongBits(value) + Double.doubleToLongBits(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1910,8 +1910,8 @@ public IntrinsicGuard(FixedWithNextNode lastInstr, ValueNode receiver, Mark mark

/**
* Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod}
* and not another method that overrides it. This should only be called if there is an intrinsic
* (i.e., an {@link InvocationPlugin}) for {@code targetMethod} and the invocation is indirect.
* and not another method that overrides it. This should only be called if there is an
* {@link InvocationPlugin} for {@code targetMethod} and the invocation is indirect.
*
* The control flow woven around the intrinsic is as follows:
*
Expand Down Expand Up @@ -2066,9 +2066,7 @@ protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, R
if (plugin != null) {

if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
// Self recursive intrinsic means the original
// method should be called.
assert !targetMethod.hasBytecodes() : "TODO: when does this happen?";
// Self recursive intrinsic means the original method should be called.
return false;
}

Expand All @@ -2088,7 +2086,7 @@ protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, R
try (DebugCloseable context = openNodeContext(targetMethod)) {
if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
return true;
return !plugin.isDecorator();
} else {
afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
}
Expand Down Expand Up @@ -3304,7 +3302,8 @@ protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock
if (isNeverExecutedCode(probability)) {
if (!graph.isOSR() || getParent() != null || graph.getEntryBCI() != trueBlock.startBci) {
NodeSourcePosition survivingSuccessorPosition = graph.trackNodeSourcePosition()
? new NodeSourcePosition(currentPosition.getCaller(), currentPosition.getMethod(), falseBlock.startBci) : null;
? new NodeSourcePosition(currentPosition.getCaller(), currentPosition.getMethod(), falseBlock.startBci)
: null;
append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true, survivingSuccessorPosition));
if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore);
Expand All @@ -3315,7 +3314,8 @@ protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock
} else if (isNeverExecutedCode(1 - probability)) {
if (!graph.isOSR() || getParent() != null || graph.getEntryBCI() != falseBlock.startBci) {
NodeSourcePosition survivingSuccessorPosition = graph.trackNodeSourcePosition()
? new NodeSourcePosition(currentPosition.getCaller(), currentPosition.getMethod(), trueBlock.startBci) : null;
? new NodeSourcePosition(currentPosition.getCaller(), currentPosition.getMethod(), trueBlock.startBci)
: null;
append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false, survivingSuccessorPosition));
if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ default boolean inlineOnly() {
return isSignaturePolymorphic();
}

/**
* Determines if this plugin only decorates the method is it associated with. That is, it
* inserts nodes prior to the invocation (e.g. some kind of marker nodes) but still expects the
* parser to process the invocation further.
*/
default boolean isDecorator() {
return false;
}

/**
* Handles invocation of a signature polymorphic method.
*
Expand Down Expand Up @@ -167,7 +176,8 @@ default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, In
* @return {@code true} if this plugin handled the invocation of {@code targetMethod}
* {@code false} if the graph builder should process the invoke further (e.g., by
* inlining it or creating an {@link Invoke} node). A plugin that does not handle an
* invocation must not modify the graph being constructed.
* invocation must not modify the graph being constructed unless it is a
* {@linkplain InvocationPlugin#isDecorator() decorator}.
*/
default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
if (isSignaturePolymorphic()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,9 @@ InvocationPlugin get(ResolvedJavaMethod method) {
}
}
if (res != null) {
if (canBeIntrinsified(declaringClass)) {
// A decorator plugin is trusted since it does not replace
// the method it intrinsifies.
if (res.isDecorator() || canBeIntrinsified(declaringClass)) {
return res;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
import java.lang.reflect.Field;
import java.util.Arrays;

import jdk.vm.ci.code.BytecodePosition;
import jdk.vm.ci.meta.SpeculationLog;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.BytecodeProvider;
Expand All @@ -63,6 +61,7 @@
import org.graalvm.compiler.nodes.calc.AbsNode;
import org.graalvm.compiler.nodes.calc.CompareNode;
import org.graalvm.compiler.nodes.calc.ConditionalNode;
import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
import org.graalvm.compiler.nodes.calc.NarrowNode;
import org.graalvm.compiler.nodes.calc.ReinterpretNode;
Expand Down Expand Up @@ -107,6 +106,7 @@
import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode;
import org.graalvm.word.LocationIdentity;

import jdk.vm.ci.code.BytecodePosition;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaConstant;
Expand All @@ -115,6 +115,7 @@
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.SpeculationLog;
import sun.misc.Unsafe;

/**
Expand Down Expand Up @@ -353,6 +354,16 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
return true;
}
});
r.register1("floatToIntBits", float.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Int, value, NodeView.DEFAULT));
ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forInt(0x7fc00000), NodeView.DEFAULT));
b.push(JavaKind.Int, result);
return true;
}
});
r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
Expand All @@ -371,6 +382,16 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
return true;
}
});
r.register1("doubleToLongBits", double.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT));
ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forLong(0x7ff8000000000000L), NodeView.DEFAULT));
b.push(JavaKind.Long, result);
return true;
}
});
r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
Expand Down Expand Up @@ -906,6 +927,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
b.add(new BlackholeNode(value));
return true;
}

@Override
public boolean isDecorator() {
return true;
}
};
String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
for (String name : names) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2018, 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
Expand Down Expand Up @@ -74,6 +74,14 @@ interface LINUX extends Platform {
interface DARWIN extends Platform {
}

/**
* Supported operating system: Darwin (MacOS).
*
* @since 1.0
*/
interface WINDOWS extends Platform {
}

/*
* Standard leaf platforms, i.e., OS-architecture combinations that we support.
*/
Expand Down Expand Up @@ -110,6 +118,22 @@ public DARWIN_AMD64() {
}
}

/**
* Supported leaf platform: Windows on x86 64-bit.
*
* @since 1.0
*/
final class WINDOWS_AMD64 implements WINDOWS, AMD64 {

/**
* Instantiates a marker instance of this platform.
*
* @since 1.0
*/
public WINDOWS_AMD64() {
}
}

/**
* Marker for elements (types, methods, or fields) that are only visible during native image
* generation and cannot be used at run time, regardless of the actual platform.
Expand Down
4 changes: 2 additions & 2 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def build(args, vm=None):
mx.log('build: Checking SubstrateVM requirements for building ...')

if not _host_os_supported():
mx.abort('build: SubstrateVM can be built only on Darwin and Linux platforms')
mx.abort('build: SubstrateVM can be built only on Darwin, Linux and Windows platforms')

global allow_native_image_build
if '--warning-as-error' in args and '--force-javac' not in args:
Expand All @@ -86,7 +86,7 @@ def build(args, vm=None):
orig_command_build(args, vm)

def _host_os_supported():
return mx.get_os() == 'linux' or mx.get_os() == 'darwin'
return mx.get_os() == 'linux' or mx.get_os() == 'darwin' or mx.get_os() == 'windows'

def _unittest_config_participant(config):
vmArgs, mainClass, mainClassArgs = config
Expand Down
Loading

0 comments on commit 147683e

Please sign in to comment.