# HG changeset patch # User Doug Simon # Date 1384959538 -3600 # Node ID 514e809bd97df7fc781fdbcfbd9373ee2b3ea187 # Parent ec3e4f35e46656d2b4830a364416f395bd0ca6e9# Parent 5341a7fca039251266da2ac05fce9fdadf5742f2 Merge. diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Nov 20 15:58:58 2013 +0100 @@ -1874,6 +1874,7 @@ printLir("After register number assignment", true); EdgeMoveOptimizer.optimize(ir); ControlFlowOptimizer.optimize(ir); + NullCheckOptimizer.optimize(ir, target.implicitNullCheckLimit); printLir("After control flow optimization", false); } }); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java Wed Nov 20 15:58:58 2013 +0100 @@ -52,12 +52,13 @@ assert host == null; TargetDescription target = createTarget(runtime.getConfig()); + HotSpotRegistersProvider registers = createRegisters(); HotSpotMetaAccessProvider metaAccess = createMetaAccess(runtime); HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target); HotSpotConstantReflectionProvider constantReflection = createConstantReflection(runtime); Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig()); HotSpotHostForeignCallsProvider foreignCalls = createForeignCalls(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters); - HotSpotHostLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls); + HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers); // Replacements cannot have speculative optimizations since they have // to be valid for the entire run of the VM. Assumptions assumptions = new Assumptions(false); @@ -65,7 +66,6 @@ Replacements replacements = createReplacements(runtime, assumptions, p); HotSpotDisassemblerProvider disassembler = createDisassembler(runtime); HotSpotSuitesProvider suites = createSuites(runtime); - HotSpotRegisters registers = createRegisters(); HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers); return createBackend(runtime, providers); @@ -75,7 +75,7 @@ return new AMD64HotSpotBackend(runtime, providers); } - protected HotSpotRegisters createRegisters() { + protected HotSpotRegistersProvider createRegisters() { return new HotSpotRegisters(AMD64.r15, AMD64.r12, AMD64.rsp); } @@ -108,8 +108,8 @@ return new HotSpotSuitesProvider(runtime); } - protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls) { - return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls); + protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) { + return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers); } protected Value[] createNativeABICallerSaveRegisters(HotSpotVMConfig config, RegisterConfig regConfig) { diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Nov 20 15:58:58 2013 +0100 @@ -76,7 +76,7 @@ } @Override - protected HotSpotProviders getProviders() { + public HotSpotProviders getProviders() { return (HotSpotProviders) super.getProviders(); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java Wed Nov 20 15:58:58 2013 +0100 @@ -31,12 +31,12 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.amd64.*; -public class AMD64HotSpotLoweringProvider extends HotSpotHostLoweringProvider { +public class AMD64HotSpotLoweringProvider extends HotSpotLoweringProvider { private AMD64ConvertSnippets.Templates convertSnippets; - public AMD64HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) { - super(runtime, metaAccess, foreignCalls); + public AMD64HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) { + super(runtime, metaAccess, foreignCalls, registers); } @Override diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Wed Nov 20 15:58:58 2013 +0100 @@ -64,6 +64,14 @@ return true; } + @Override + public void completeInitialization() { + final HotSpotProviders providers = getProviders(); + HotSpotVMConfig config = getRuntime().getConfig(); + final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer(); + lowerer.initialize(providers, config); + } + /** * Use the HSAIL register set when the compilation target is HSAIL. */ diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java Wed Nov 20 15:58:58 2013 +0100 @@ -38,11 +38,12 @@ public HSAILHotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) { HotSpotProviders host = hostBackend.getProviders(); + HotSpotRegisters registers = new HotSpotRegisters(Register.None, Register.None, Register.None); HotSpotMetaAccessProvider metaAccess = host.getMetaAccess(); HSAILHotSpotCodeCacheProvider codeCache = new HSAILHotSpotCodeCacheProvider(runtime, createTarget()); ConstantReflectionProvider constantReflection = host.getConstantReflection(); HotSpotForeignCallsProvider foreignCalls = new HSAILHotSpotForeignCallsProvider(runtime, metaAccess, codeCache); - LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(host.getLowerer()); + LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers); // Replacements cannot have speculative optimizations since they have // to be valid for the entire run of the VM. Assumptions assumptions = new Assumptions(false); @@ -50,7 +51,6 @@ Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, host.getReplacements()); HotSpotDisassemblerProvider disassembler = host.getDisassembler(); HotSpotSuitesProvider suites = host.getSuites(); - HotSpotRegisters registers = new HotSpotRegisters(Register.None, Register.None, Register.None); HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers); return new HSAILHotSpotBackend(runtime, providers); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java Wed Nov 20 15:58:58 2013 +0100 @@ -22,30 +22,27 @@ */ package com.oracle.graal.hotspot.hsail; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; -public class HSAILHotSpotLoweringProvider implements LoweringProvider { +public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider { - private LoweringProvider host; - - public HSAILHotSpotLoweringProvider(LoweringProvider host) { - this.host = host; + public HSAILHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) { + super(runtime, metaAccess, foreignCalls, registers); } + @Override public void lower(Node n, LoweringTool tool) { if (n instanceof ConvertNode) { - // TODO return; } else { - host.lower(n, tool); + super.lower(n, tool); } } - public ValueNode reconstructArrayIndex(LocationNode location) { - throw GraalInternalError.unimplemented(); - } } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Wed Nov 20 15:58:58 2013 +0100 @@ -62,8 +62,8 @@ @Override public StructuredGraph getSnippet(ResolvedJavaMethod method) { - // TODO must work in cooperation with HSAILHotSpotLoweringProvider - return null; + // Must work in cooperation with HSAILHotSpotLoweringProvider + return host.getSnippet(method); } @Override diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Wed Nov 20 15:58:58 2013 +0100 @@ -50,12 +50,13 @@ assert host == null; TargetDescription target = createTarget(); + HotSpotRegistersProvider registers = new HotSpotRegisters(Register.None, Register.None, Register.None); // FIXME HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime); HotSpotCodeCacheProvider codeCache = new SPARCHotSpotCodeCacheProvider(runtime, target); HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime); Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig()); HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters); - LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls); + LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers); // Replacements cannot have speculative optimizations since they have // to be valid for the entire run of the VM. Assumptions assumptions = new Assumptions(false); @@ -63,7 +64,6 @@ HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions); HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime); HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime); - HotSpotRegisters registers = new HotSpotRegisters(Register.None, Register.None, Register.None); // FIXME HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers); return new SPARCHotSpotBackend(runtime, providers); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Nov 20 15:58:58 2013 +0100 @@ -57,7 +57,7 @@ } @Override - protected HotSpotProviders getProviders() { + public HotSpotProviders getProviders() { return (HotSpotProviders) super.getProviders(); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java Wed Nov 20 15:58:58 2013 +0100 @@ -30,10 +30,10 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; -public class SPARCHotSpotLoweringProvider extends HotSpotHostLoweringProvider { +public class SPARCHotSpotLoweringProvider extends HotSpotLoweringProvider { - public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) { - super(runtime, metaAccess, foreignCalls); + public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) { + super(runtime, metaAccess, foreignCalls, registers); } @Override diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Nov 20 15:58:58 2013 +0100 @@ -45,7 +45,7 @@ final HotSpotProviders providers = getProviders(); HotSpotVMConfig config = getRuntime().getConfig(); HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls(); - final HotSpotHostLoweringProvider lowerer = (HotSpotHostLoweringProvider) providers.getLowerer(); + final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer(); foreignCalls.initialize(providers, config); lowerer.initialize(providers, config); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Wed Nov 20 15:58:58 2013 +0100 @@ -25,6 +25,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -55,4 +56,6 @@ * Gets a stack slot for a lock at a given lock nesting depth. */ StackSlot getLockSlot(int lockDepth); + + HotSpotProviders getProviders(); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Wed Nov 20 15:58:58 2013 +0100 @@ -39,12 +39,7 @@ * Compiles a method to machine code. This method is called from the VM * (VMToCompiler::compileMethod). */ - void compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking) throws Throwable; - - /** - * Compiles a method to machine code. - */ - void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) throws Throwable; + void compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking); /** * Notifies this object of statistics for a completed compilation. @@ -60,7 +55,7 @@ */ void notifyCompilationDone(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, TimeUnit timeUnit, HotSpotInstalledCode installedCode); - void shutdownCompiler() throws Throwable; + void shutdownCompiler() throws Exception; void startCompiler(boolean bootstrapEnabled, long statsAddress) throws Throwable; diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Nov 20 15:58:58 2013 +0100 @@ -30,6 +30,7 @@ import java.io.*; import java.lang.reflect.*; +import java.security.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -352,11 +353,18 @@ } } - public void shutdownCompiler() throws Throwable { + public void shutdownCompiler() throws Exception { try { assert !CompilationTask.withinEnqueue.get(); CompilationTask.withinEnqueue.set(Boolean.TRUE); - shutdownCompileQueue(compileQueue); + // We have to use a privileged action here because shutting down the compiler might be + // called from user code which very likely contains unprivileged frames. + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Void run() throws Exception { + shutdownCompileQueue(compileQueue); + return null; + } + }); } finally { CompilationTask.withinEnqueue.set(Boolean.FALSE); } @@ -535,15 +543,22 @@ } @Override - public void compileMethod(long metaspaceMethod, final HotSpotResolvedObjectType holder, final int entryBCI, boolean blocking) throws Throwable { - HotSpotResolvedJavaMethod method = holder.createMethod(metaspaceMethod); - compileMethod(method, entryBCI, blocking); + public void compileMethod(long metaspaceMethod, final HotSpotResolvedObjectType holder, final int entryBCI, final boolean blocking) { + final HotSpotResolvedJavaMethod method = holder.createMethod(metaspaceMethod); + // We have to use a privileged action here because compilations are enqueued from user code + // which very likely contains unprivileged frames. + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + compileMethod(method, entryBCI, blocking); + return null; + } + }); } /** * Compiles a method to machine code. */ - public void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, boolean blocking) throws Throwable { + public void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, final boolean blocking) { boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI; if (osrCompilation && bootstrapRunning) { // no OSR compilations during bootstrap - the compiler is just too slow at this point, diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java Wed Nov 20 15:58:23 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,725 +0,0 @@ -/* - * Copyright (c) 2011, 2012, 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 com.oracle.graal.hotspot.meta; - -import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.api.meta.DeoptimizationAction.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.api.meta.LocationIdentity.*; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider.*; -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; -import static com.oracle.graal.nodes.java.ArrayLengthNode.*; -import static com.oracle.graal.phases.GraalOptions.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.debug.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.debug.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.replacements.*; - -/** - * HotSpot implementation of {@link LoweringProvider}. - */ -public class HotSpotHostLoweringProvider implements LoweringProvider { - - protected final HotSpotGraalRuntime runtime; - protected final MetaAccessProvider metaAccess; - protected final ForeignCallsProvider foreignCalls; - - private CheckCastDynamicSnippets.Templates checkcastDynamicSnippets; - private InstanceOfSnippets.Templates instanceofSnippets; - private NewObjectSnippets.Templates newObjectSnippets; - private MonitorSnippets.Templates monitorSnippets; - protected WriteBarrierSnippets.Templates writeBarrierSnippets; - private BoxingSnippets.Templates boxingSnippets; - private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; - private UnsafeLoadSnippets.Templates unsafeLoadSnippets; - - public HotSpotHostLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) { - this.runtime = runtime; - this.metaAccess = metaAccess; - this.foreignCalls = foreignCalls; - } - - public void initialize(HotSpotProviders providers, HotSpotVMConfig config) { - TargetDescription target = providers.getCodeCache().getTarget(); - checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target); - instanceofSnippets = new InstanceOfSnippets.Templates(providers, target); - newObjectSnippets = new NewObjectSnippets.Templates(providers, target); - monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking); - writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target); - boxingSnippets = new BoxingSnippets.Templates(providers, target); - exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target); - unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target); - providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target)); - } - - @Override - public void lower(Node n, LoweringTool tool) { - HotSpotVMConfig config = runtime.getConfig(); - StructuredGraph graph = (StructuredGraph) n.graph(); - - Kind wordKind = runtime.getTarget().wordKind; - if (n instanceof ArrayLengthNode) { - ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; - ValueNode array = arrayLengthNode.array(); - ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(), - BarrierType.NONE, false)); - tool.createNullCheckGuard(arrayLengthRead, array); - graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); - } else if (n instanceof Invoke) { - Invoke invoke = (Invoke) n; - if (invoke.callTarget() instanceof MethodCallTargetNode) { - - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); - NodeInputList parameters = callTarget.arguments(); - ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); - GuardingNode receiverNullCheck = null; - if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) { - receiverNullCheck = tool.createNullCheckGuard(invoke, receiver); - } - JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); - - LoweredCallTargetNode loweredCallTarget = null; - if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) { - - HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); - if (!hsMethod.getDeclaringClass().isInterface()) { - if (hsMethod.isInVirtualMethodTable()) { - int vtableEntryOffset = hsMethod.vtableEntryOffset(); - assert vtableEntryOffset > 0; - FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck); - - ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod); - // We use LocationNode.ANY_LOCATION for the reads that access the - // compiled code entry as HotSpot does not guarantee they are final - // values. - ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), - StampFactory.forKind(wordKind), BarrierType.NONE, false)); - - loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), - CallingConvention.Type.JavaCall)); - - graph.addBeforeFixed(invoke.asNode(), metaspaceMethod); - graph.addAfterFixed(metaspaceMethod, compiledEntry); - } - } - } - - if (loweredCallTarget == null) { - loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, - callTarget.invokeKind())); - } - callTarget.replaceAndDelete(loweredCallTarget); - } - } else if (n instanceof LoadFieldNode) { - LoadFieldNode loadField = (LoadFieldNode) n; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); - ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object(); - assert loadField.kind() != Kind.Illegal; - BarrierType barrierType = getFieldLoadBarrierType(field); - ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); - graph.replaceFixedWithFixed(loadField, memoryRead); - tool.createNullCheckGuard(memoryRead, object); - - if (loadField.isVolatile()) { - MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); - graph.addBeforeFixed(memoryRead, preMembar); - MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); - graph.addAfterFixed(memoryRead, postMembar); - } - } else if (n instanceof StoreFieldNode) { - StoreFieldNode storeField = (StoreFieldNode) n; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); - ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object(); - BarrierType barrierType = getFieldStoreBarrierType(storeField); - WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object)); - tool.createNullCheckGuard(memoryWrite, object); - memoryWrite.setStateAfter(storeField.stateAfter()); - graph.replaceFixedWithFixed(storeField, memoryWrite); - FixedWithNextNode last = memoryWrite; - FixedWithNextNode first = memoryWrite; - - if (storeField.isVolatile()) { - MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); - graph.addBeforeFixed(first, preMembar); - MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); - graph.addAfterFixed(last, postMembar); - } - } else if (n instanceof CompareAndSwapNode) { - // Separate out GC barrier semantics - CompareAndSwapNode cas = (CompareAndSwapNode) n; - LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); - LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas), - cas.expected().kind() == Kind.Object)); - atomicNode.setStateAfter(cas.stateAfter()); - graph.replaceFixedWithFixed(cas, atomicNode); - } else if (n instanceof LoadIndexedNode) { - LoadIndexedNode loadIndexed = (LoadIndexedNode) n; - GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool); - Kind elementKind = loadIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false); - ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object)); - memoryRead.setGuard(boundsCheck); - graph.replaceFixedWithFixed(loadIndexed, memoryRead); - } else if (n instanceof StoreIndexedNode) { - StoreIndexedNode storeIndexed = (StoreIndexedNode) n; - GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool); - Kind elementKind = storeIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false); - ValueNode value = storeIndexed.value(); - ValueNode array = storeIndexed.array(); - - CheckCastNode checkcastNode = null; - CheckCastDynamicNode checkcastDynamicNode = null; - if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) { - // Store check! - ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array); - if (arrayType != null && ObjectStamp.isExactType(array)) { - ResolvedJavaType elementType = arrayType.getComponentType(); - if (!MetaUtil.isJavaLangObject(elementType)) { - checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true)); - graph.addBeforeFixed(storeIndexed, checkcastNode); - value = checkcastNode; - } - } else { - FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck); - LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); - /* - * Anchor the read of the element klass to the cfg, because it is only valid - * when arrayClass is an object class, which might not be the case in other - * parts of the compiled method. - */ - FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed))); - checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true)); - graph.addBeforeFixed(storeIndexed, checkcastDynamicNode); - value = checkcastDynamicNode; - } - } - BarrierType barrierType = getArrayStoreBarrierType(storeIndexed); - WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object)); - memoryWrite.setGuard(boundsCheck); - memoryWrite.setStateAfter(storeIndexed.stateAfter()); - graph.replaceFixedWithFixed(storeIndexed, memoryWrite); - - // Lower the associated checkcast node. - if (checkcastNode != null) { - checkcastNode.lower(tool); - } else if (checkcastDynamicNode != null) { - checkcastDynamicSnippets.lower(checkcastDynamicNode); - } - } else if (n instanceof UnsafeLoadNode) { - UnsafeLoadNode load = (UnsafeLoadNode) n; - if (load.getGuardingCondition() != null) { - boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); - ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition())); - LocationNode location = createLocation(load); - ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible)); - load.replaceAtUsages(memoryRead); - graph.replaceFixedWithFixed(load, valueAnchorNode); - graph.addAfterFixed(valueAnchorNode, memoryRead); - } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) { - assert load.kind() != Kind.Illegal; - boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); - if (addReadBarrier(load)) { - unsafeLoadSnippets.lower(load, tool); - } else { - LocationNode location = createLocation(load); - ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible)); - // An unsafe read must not float outside its block otherwise - // it may float above an explicit null check on its object. - memoryRead.setGuard(AbstractBeginNode.prevBegin(load)); - graph.replaceFixedWithFixed(load, memoryRead); - } - } - } else if (n instanceof UnsafeStoreNode) { - UnsafeStoreNode store = (UnsafeStoreNode) n; - LocationNode location = createLocation(store); - ValueNode object = store.object(); - BarrierType barrierType = getUnsafeStoreBarrierType(store); - WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object)); - write.setStateAfter(store.stateAfter()); - graph.replaceFixedWithFixed(store, write); - } else if (n instanceof LoadHubNode) { - LoadHubNode loadHub = (LoadHubNode) n; - assert loadHub.kind() == wordKind; - ValueNode object = loadHub.object(); - GuardingNode guard = loadHub.getGuard(); - FloatingReadNode hub = createReadHub(graph, wordKind, object, guard); - graph.replaceFloating(loadHub, hub); - } else if (n instanceof LoadMethodNode) { - LoadMethodNode loadMethodNode = (LoadMethodNode) n; - ResolvedJavaMethod method = loadMethodNode.getMethod(); - ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method); - graph.replaceFixed(loadMethodNode, metaspaceMethod); - } else if (n instanceof StoreHubNode) { - StoreHubNode storeHub = (StoreHubNode) n; - WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue()); - graph.replaceFixed(storeHub, hub); - } else if (n instanceof CommitAllocationNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - CommitAllocationNode commit = (CommitAllocationNode) n; - ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()]; - BitSet omittedValues = new BitSet(); - int valuePos = 0; - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); - int entryCount = virtual.entryCount(); - FixedWithNextNode newObject; - if (virtual instanceof VirtualInstanceNode) { - newObject = graph.add(new NewInstanceNode(virtual.type(), true)); - graph.addBeforeFixed(commit, newObject); - allocations[objIndex] = newObject; - for (int i = 0; i < entryCount; i++) { - ValueNode value = commit.getValues().get(valuePos); - if (value instanceof VirtualObjectNode) { - value = allocations[commit.getVirtualObjects().indexOf(value)]; - } - if (value == null) { - omittedValues.set(valuePos); - } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - // Constant.illegal is always the defaultForKind, so it is skipped - VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; - Kind accessKind; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i); - if (value.kind().getStackKind() != field.getKind().getStackKind()) { - assert value.kind() == Kind.Long || value.kind() == Kind.Double; - accessKind = value.kind(); - } else { - accessKind = field.getKind(); - } - ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph); - BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; - WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object); - graph.addAfterFixed(newObject, graph.add(write)); - } - valuePos++; - } - } else { - ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); - newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true)); - graph.addBeforeFixed(commit, newObject); - allocations[objIndex] = newObject; - for (int i = 0; i < entryCount; i++) { - ValueNode value = commit.getValues().get(valuePos); - if (value instanceof VirtualObjectNode) { - value = allocations[commit.getVirtualObjects().indexOf(value)]; - } - if (value == null) { - omittedValues.set(valuePos); - } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - // Constant.illegal is always the defaultForKind, so it is skipped - Kind componentKind = element.getKind(); - Kind accessKind; - Kind valueKind = value.kind(); - if (valueKind.getStackKind() != componentKind.getStackKind()) { - // Given how Truffle uses unsafe, it can happen that - // valueKind is Kind.Int - // assert valueKind == Kind.Long || valueKind == Kind.Double; - accessKind = valueKind; - } else { - accessKind = componentKind; - } - - int scale = getScalingFactor(componentKind); - ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph); - BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; - WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object); - graph.addAfterFixed(newObject, graph.add(write)); - } - valuePos++; - } - } - } - valuePos = 0; - - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); - int entryCount = virtual.entryCount(); - ValueNode newObject = allocations[objIndex]; - if (virtual instanceof VirtualInstanceNode) { - for (int i = 0; i < entryCount; i++) { - if (omittedValues.get(valuePos)) { - ValueNode value = commit.getValues().get(valuePos); - assert value instanceof VirtualObjectNode; - ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; - if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { - VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; - assert virtualInstance.field(i).getKind() == Kind.Object; - WriteNode write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), - BarrierType.IMPRECISE, true); - graph.addBeforeFixed(commit, graph.add(write)); - } - } - valuePos++; - } - } else { - ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); - for (int i = 0; i < entryCount; i++) { - if (omittedValues.get(valuePos)) { - ValueNode value = commit.getValues().get(valuePos); - assert value instanceof VirtualObjectNode; - ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; - if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { - assert allocValue.kind() == Kind.Object; - WriteNode write = new WriteNode(newObject, allocValue, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, - true); - graph.addBeforeFixed(commit, graph.add(write)); - } - } - valuePos++; - } - } - } - - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex])); - allocations[objIndex] = anchor; - graph.addBeforeFixed(commit, anchor); - } - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - for (int lockDepth : commit.getLocks().get(objIndex)) { - MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth)); - graph.addBeforeFixed(commit, enter); - enter.lower(tool); - } - } - for (Node usage : commit.usages().snapshot()) { - AllocatedObjectNode addObject = (AllocatedObjectNode) usage; - int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject()); - graph.replaceFloating(addObject, allocations[index]); - } - graph.removeFixed(commit); - } - } else if (n instanceof OSRStartNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - OSRStartNode osrStart = (OSRStartNode) n; - StartNode newStart = graph.add(new StartNode()); - LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind))); - ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer)); - migrationEnd.setStateAfter(osrStart.stateAfter()); - - newStart.setNext(migrationEnd); - FixedNode next = osrStart.next(); - osrStart.setNext(null); - migrationEnd.setNext(next); - graph.setStart(newStart); - - // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) - int localsOffset = (graph.method().getMaxLocals() - 1) * 8; - for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { - int size = FrameStateBuilder.stackSlots(osrLocal.kind()); - int offset = localsOffset - (osrLocal.index() + size - 1) * 8; - IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1); - ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false)); - osrLocal.replaceAndDelete(load); - graph.addBeforeFixed(migrationEnd, load); - } - osrStart.replaceAtUsages(newStart); - osrStart.safeDelete(); - } - } else if (n instanceof DynamicCounterNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { - BenchmarkCounters.lower((DynamicCounterNode) n, runtime.getHostProviders().getRegisters(), runtime.getConfig(), wordKind); - } - } else if (n instanceof CheckCastDynamicNode) { - checkcastDynamicSnippets.lower((CheckCastDynamicNode) n); - } else if (n instanceof InstanceOfNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - instanceofSnippets.lower((InstanceOfNode) n, tool); - } - } else if (n instanceof InstanceOfDynamicNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - instanceofSnippets.lower((InstanceOfDynamicNode) n, tool); - } - } else if (n instanceof NewInstanceNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { - newObjectSnippets.lower((NewInstanceNode) n); - } - } else if (n instanceof NewArrayNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { - newObjectSnippets.lower((NewArrayNode) n); - } - } else if (n instanceof DynamicNewArrayNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { - newObjectSnippets.lower((DynamicNewArrayNode) n); - } - } else if (n instanceof MonitorEnterNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - monitorSnippets.lower((MonitorEnterNode) n, tool); - } - } else if (n instanceof MonitorExitNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - monitorSnippets.lower((MonitorExitNode) n, tool); - } - } else if (n instanceof G1PreWriteBarrier) { - writeBarrierSnippets.lower((G1PreWriteBarrier) n, tool); - } else if (n instanceof G1PostWriteBarrier) { - writeBarrierSnippets.lower((G1PostWriteBarrier) n, tool); - } else if (n instanceof G1ReferentFieldReadBarrier) { - writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, tool); - } else if (n instanceof SerialWriteBarrier) { - writeBarrierSnippets.lower((SerialWriteBarrier) n, tool); - } else if (n instanceof SerialArrayRangeWriteBarrier) { - writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool); - } else if (n instanceof G1ArrayRangePreWriteBarrier) { - writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, tool); - } else if (n instanceof G1ArrayRangePostWriteBarrier) { - writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, tool); - } else if (n instanceof NewMultiArrayNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { - newObjectSnippets.lower((NewMultiArrayNode) n); - } - } else if (n instanceof LoadExceptionObjectNode) { - exceptionObjectSnippets.lower((LoadExceptionObjectNode) n); - } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) { - // Nothing to do for division nodes. The HotSpot signal handler catches divisions by - // zero and the MIN_VALUE / -1 cases. - } else if (n instanceof BoxNode) { - boxingSnippets.lower((BoxNode) n, tool); - } else if (n instanceof UnboxNode) { - boxingSnippets.lower((UnboxNode) n, tool); - } else { - assert false : "Node implementing Lowerable not handled: " + n; - throw GraalInternalError.shouldNotReachHere(); - } - } - - private static LocationNode createLocation(UnsafeAccessNode access) { - ValueNode offset = access.offset(); - if (offset.isConstant()) { - long offsetValue = offset.asConstant().asLong(); - return ConstantLocationNode.create(access.getLocationIdentity(), access.accessKind(), offsetValue, access.graph()); - } - - long displacement = 0; - int indexScaling = 1; - if (offset instanceof IntegerAddNode) { - IntegerAddNode integerAddNode = (IntegerAddNode) offset; - if (integerAddNode.y() instanceof ConstantNode) { - displacement = integerAddNode.y().asConstant().asLong(); - offset = integerAddNode.x(); - } - } - - if (offset instanceof LeftShiftNode) { - LeftShiftNode leftShiftNode = (LeftShiftNode) offset; - if (leftShiftNode.y() instanceof ConstantNode) { - long shift = leftShiftNode.y().asConstant().asLong(); - if (shift >= 1 && shift <= 3) { - if (shift == 1) { - indexScaling = 2; - } else if (shift == 2) { - indexScaling = 4; - } else { - indexScaling = 8; - } - offset = leftShiftNode.x(); - } - } - } - - return IndexedLocationNode.create(access.getLocationIdentity(), access.accessKind(), displacement, offset, access.graph(), indexScaling); - } - - private static boolean addReadBarrier(UnsafeLoadNode load) { - if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object && - !ObjectStamp.isObjectAlwaysNull(load.object())) { - ResolvedJavaType type = ObjectStamp.typeOrNull(load.object()); - if (type != null && !type.isArray()) { - return true; - } - } - return false; - } - - private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) { - HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; - assert !hsMethod.getDeclaringClass().isInterface(); - assert hsMethod.isInVirtualMethodTable(); - - int vtableEntryOffset = hsMethod.vtableEntryOffset(); - assert vtableEntryOffset > 0; - // We use LocationNode.ANY_LOCATION for the reads that access the vtable - // entry as HotSpot does not guarantee that this is a final value. - ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false)); - return metaspaceMethod; - } - - private FloatingReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) { - HotSpotVMConfig config = runtime.getConfig(); - LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph); - assert !object.isConstant() || object.asConstant().isNull(); - return graph.unique(new FloatingReadNode(object, location, null, StampFactory.forKind(wordKind), guard, BarrierType.NONE, config.useCompressedClassPointers)); - } - - private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) { - HotSpotVMConfig config = runtime.getConfig(); - LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph); - assert !object.isConstant() || object.asConstant().isNull(); - return graph.add(new WriteNode(object, value, location, BarrierType.NONE, config.useCompressedClassPointers)); - } - - private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) { - BarrierType barrierType = BarrierType.NONE; - if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) { - barrierType = BarrierType.PRECISE; - } - return barrierType; - } - - private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) { - BarrierType barrierType = BarrierType.NONE; - if (storeField.field().getKind() == Kind.Object) { - barrierType = BarrierType.IMPRECISE; - } - return barrierType; - } - - private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) { - BarrierType barrierType = BarrierType.NONE; - if (store.elementKind() == Kind.Object) { - barrierType = BarrierType.PRECISE; - } - return barrierType; - } - - private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) { - BarrierType barrierType = BarrierType.NONE; - if (store.value().kind() == Kind.Object) { - ResolvedJavaType type = ObjectStamp.typeOrNull(store.object()); - if (type != null && !type.isArray()) { - barrierType = BarrierType.IMPRECISE; - } else { - barrierType = BarrierType.PRECISE; - } - } - return barrierType; - } - - private static BarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) { - BarrierType barrierType = BarrierType.NONE; - if (cas.expected().kind() == Kind.Object) { - ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object()); - if (type != null && !type.isArray()) { - barrierType = BarrierType.IMPRECISE; - } else { - barrierType = BarrierType.PRECISE; - } - } - return barrierType; - } - - protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) { - LocationIdentity loc = initialization ? INIT_LOCATION : field; - return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph); - } - - public int getScalingFactor(Kind kind) { - if (useCompressedOops() && kind == Kind.Object) { - return this.runtime.getTarget().arch.getSizeInBytes(Kind.Int); - } else { - return this.runtime.getTarget().arch.getSizeInBytes(kind); - } - } - - protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) { - LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind); - int scale = getScalingFactor(elementKind); - return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale); - } - - @Override - public ValueNode reconstructArrayIndex(LocationNode location) { - Kind elementKind = location.getValueKind(); - assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind)); - - long base; - ValueNode index; - int scale = getScalingFactor(elementKind); - - if (location instanceof ConstantLocationNode) { - base = ((ConstantLocationNode) location).getDisplacement(); - index = null; - } else if (location instanceof IndexedLocationNode) { - IndexedLocationNode indexedLocation = (IndexedLocationNode) location; - assert indexedLocation.getIndexScaling() == scale; - base = indexedLocation.getDisplacement(); - index = indexedLocation.getIndex(); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - - base -= getArrayBaseOffset(elementKind); - assert base >= 0 && base % scale == 0; - - base /= scale; - assert NumUtil.isInt(base); - - StructuredGraph graph = location.graph(); - if (index == null) { - return ConstantNode.forInt((int) base, graph); - } else { - if (base == 0) { - return index; - } else { - return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index); - } - } - } - - private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { - StructuredGraph g = n.graph(); - ValueNode array = n.array(); - ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection()); - if (arrayLength == null) { - Stamp stamp = StampFactory.positiveInt(); - ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false)); - g.addBeforeFixed(n, readArrayLength); - tool.createNullCheckGuard(readArrayLength, array); - arrayLength = readArrayLength; - } - - return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); - } - -} diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Nov 20 15:58:58 2013 +0100 @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2011, 2012, 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 com.oracle.graal.hotspot.meta; + +import static com.oracle.graal.api.code.MemoryBarriers.*; +import static com.oracle.graal.api.meta.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.api.meta.LocationIdentity.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; +import static com.oracle.graal.nodes.java.ArrayLengthNode.*; +import static com.oracle.graal.phases.GraalOptions.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.debug.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.HeapAccess.BarrierType; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.replacements.*; + +/** + * HotSpot implementation of {@link LoweringProvider}. + */ +public class HotSpotLoweringProvider implements LoweringProvider { + + protected final HotSpotGraalRuntime runtime; + protected final MetaAccessProvider metaAccess; + protected final ForeignCallsProvider foreignCalls; + protected final HotSpotRegistersProvider registers; + + protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets; + protected InstanceOfSnippets.Templates instanceofSnippets; + protected NewObjectSnippets.Templates newObjectSnippets; + protected MonitorSnippets.Templates monitorSnippets; + protected WriteBarrierSnippets.Templates writeBarrierSnippets; + protected BoxingSnippets.Templates boxingSnippets; + protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; + protected UnsafeLoadSnippets.Templates unsafeLoadSnippets; + + public HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) { + this.runtime = runtime; + this.metaAccess = metaAccess; + this.foreignCalls = foreignCalls; + this.registers = registers; + } + + public void initialize(HotSpotProviders providers, HotSpotVMConfig config) { + TargetDescription target = providers.getCodeCache().getTarget(); + checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target); + instanceofSnippets = new InstanceOfSnippets.Templates(providers, target); + newObjectSnippets = new NewObjectSnippets.Templates(providers, target); + monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking); + writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target); + boxingSnippets = new BoxingSnippets.Templates(providers, target); + exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target); + unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target); + providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target)); + } + + @Override + public void lower(Node n, LoweringTool tool) { + HotSpotVMConfig config = runtime.getConfig(); + StructuredGraph graph = (StructuredGraph) n.graph(); + + Kind wordKind = runtime.getTarget().wordKind; + if (n instanceof ArrayLengthNode) { + ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; + ValueNode array = arrayLengthNode.array(); + ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(), + BarrierType.NONE, false)); + tool.createNullCheckGuard(arrayLengthRead, array); + graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); + } else if (n instanceof Invoke) { + Invoke invoke = (Invoke) n; + if (invoke.callTarget() instanceof MethodCallTargetNode) { + + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + NodeInputList parameters = callTarget.arguments(); + ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); + GuardingNode receiverNullCheck = null; + if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) { + receiverNullCheck = tool.createNullCheckGuard(invoke, receiver); + } + JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); + + LoweredCallTargetNode loweredCallTarget = null; + if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) { + + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + if (!hsMethod.getDeclaringClass().isInterface()) { + if (hsMethod.isInVirtualMethodTable()) { + int vtableEntryOffset = hsMethod.vtableEntryOffset(); + assert vtableEntryOffset > 0; + FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck); + + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod); + // We use LocationNode.ANY_LOCATION for the reads that access the + // compiled code entry as HotSpot does not guarantee they are final + // values. + ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), + StampFactory.forKind(wordKind), BarrierType.NONE, false)); + + loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), + CallingConvention.Type.JavaCall)); + + graph.addBeforeFixed(invoke.asNode(), metaspaceMethod); + graph.addAfterFixed(metaspaceMethod, compiledEntry); + } + } + } + + if (loweredCallTarget == null) { + loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, + callTarget.invokeKind())); + } + callTarget.replaceAndDelete(loweredCallTarget); + } + } else if (n instanceof LoadFieldNode) { + LoadFieldNode loadField = (LoadFieldNode) n; + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); + ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object(); + assert loadField.kind() != Kind.Illegal; + BarrierType barrierType = getFieldLoadBarrierType(field); + ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); + graph.replaceFixedWithFixed(loadField, memoryRead); + tool.createNullCheckGuard(memoryRead, object); + + if (loadField.isVolatile()) { + MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); + graph.addBeforeFixed(memoryRead, preMembar); + MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); + graph.addAfterFixed(memoryRead, postMembar); + } + } else if (n instanceof StoreFieldNode) { + StoreFieldNode storeField = (StoreFieldNode) n; + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); + ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object(); + BarrierType barrierType = getFieldStoreBarrierType(storeField); + WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object)); + tool.createNullCheckGuard(memoryWrite, object); + memoryWrite.setStateAfter(storeField.stateAfter()); + graph.replaceFixedWithFixed(storeField, memoryWrite); + FixedWithNextNode last = memoryWrite; + FixedWithNextNode first = memoryWrite; + + if (storeField.isVolatile()) { + MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); + graph.addBeforeFixed(first, preMembar); + MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); + graph.addAfterFixed(last, postMembar); + } + } else if (n instanceof CompareAndSwapNode) { + // Separate out GC barrier semantics + CompareAndSwapNode cas = (CompareAndSwapNode) n; + LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); + LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas), + cas.expected().kind() == Kind.Object)); + atomicNode.setStateAfter(cas.stateAfter()); + graph.replaceFixedWithFixed(cas, atomicNode); + } else if (n instanceof LoadIndexedNode) { + LoadIndexedNode loadIndexed = (LoadIndexedNode) n; + GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool); + Kind elementKind = loadIndexed.elementKind(); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false); + ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object)); + memoryRead.setGuard(boundsCheck); + graph.replaceFixedWithFixed(loadIndexed, memoryRead); + } else if (n instanceof StoreIndexedNode) { + StoreIndexedNode storeIndexed = (StoreIndexedNode) n; + GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool); + Kind elementKind = storeIndexed.elementKind(); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false); + ValueNode value = storeIndexed.value(); + ValueNode array = storeIndexed.array(); + + CheckCastNode checkcastNode = null; + CheckCastDynamicNode checkcastDynamicNode = null; + if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) { + // Store check! + ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array); + if (arrayType != null && ObjectStamp.isExactType(array)) { + ResolvedJavaType elementType = arrayType.getComponentType(); + if (!MetaUtil.isJavaLangObject(elementType)) { + checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true)); + graph.addBeforeFixed(storeIndexed, checkcastNode); + value = checkcastNode; + } + } else { + FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck); + LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); + /* + * Anchor the read of the element klass to the cfg, because it is only valid + * when arrayClass is an object class, which might not be the case in other + * parts of the compiled method. + */ + FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed))); + checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true)); + graph.addBeforeFixed(storeIndexed, checkcastDynamicNode); + value = checkcastDynamicNode; + } + } + BarrierType barrierType = getArrayStoreBarrierType(storeIndexed); + WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object)); + memoryWrite.setGuard(boundsCheck); + memoryWrite.setStateAfter(storeIndexed.stateAfter()); + graph.replaceFixedWithFixed(storeIndexed, memoryWrite); + + // Lower the associated checkcast node. + if (checkcastNode != null) { + checkcastNode.lower(tool); + } else if (checkcastDynamicNode != null) { + checkcastDynamicSnippets.lower(checkcastDynamicNode); + } + } else if (n instanceof UnsafeLoadNode) { + UnsafeLoadNode load = (UnsafeLoadNode) n; + if (load.getGuardingCondition() != null) { + boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); + ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition())); + LocationNode location = createLocation(load); + ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible)); + load.replaceAtUsages(memoryRead); + graph.replaceFixedWithFixed(load, valueAnchorNode); + graph.addAfterFixed(valueAnchorNode, memoryRead); + } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) { + assert load.kind() != Kind.Illegal; + boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); + if (addReadBarrier(load)) { + unsafeLoadSnippets.lower(load, tool); + } else { + LocationNode location = createLocation(load); + ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible)); + // An unsafe read must not float outside its block otherwise + // it may float above an explicit null check on its object. + memoryRead.setGuard(AbstractBeginNode.prevBegin(load)); + graph.replaceFixedWithFixed(load, memoryRead); + } + } + } else if (n instanceof UnsafeStoreNode) { + UnsafeStoreNode store = (UnsafeStoreNode) n; + LocationNode location = createLocation(store); + ValueNode object = store.object(); + BarrierType barrierType = getUnsafeStoreBarrierType(store); + WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object)); + write.setStateAfter(store.stateAfter()); + graph.replaceFixedWithFixed(store, write); + } else if (n instanceof LoadHubNode) { + LoadHubNode loadHub = (LoadHubNode) n; + assert loadHub.kind() == wordKind; + ValueNode object = loadHub.object(); + GuardingNode guard = loadHub.getGuard(); + FloatingReadNode hub = createReadHub(graph, wordKind, object, guard); + graph.replaceFloating(loadHub, hub); + } else if (n instanceof LoadMethodNode) { + LoadMethodNode loadMethodNode = (LoadMethodNode) n; + ResolvedJavaMethod method = loadMethodNode.getMethod(); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method); + graph.replaceFixed(loadMethodNode, metaspaceMethod); + } else if (n instanceof StoreHubNode) { + StoreHubNode storeHub = (StoreHubNode) n; + WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue()); + graph.replaceFixed(storeHub, hub); + } else if (n instanceof CommitAllocationNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + CommitAllocationNode commit = (CommitAllocationNode) n; + ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()]; + BitSet omittedValues = new BitSet(); + int valuePos = 0; + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + FixedWithNextNode newObject; + if (virtual instanceof VirtualInstanceNode) { + newObject = graph.add(new NewInstanceNode(virtual.type(), true)); + graph.addBeforeFixed(commit, newObject); + allocations[objIndex] = newObject; + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos); + if (value instanceof VirtualObjectNode) { + value = allocations[commit.getVirtualObjects().indexOf(value)]; + } + if (value == null) { + omittedValues.set(valuePos); + } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { + // Constant.illegal is always the defaultForKind, so it is skipped + VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; + Kind accessKind; + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i); + if (value.kind().getStackKind() != field.getKind().getStackKind()) { + assert value.kind() == Kind.Long || value.kind() == Kind.Double; + accessKind = value.kind(); + } else { + accessKind = field.getKind(); + } + ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph); + BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; + WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object); + graph.addAfterFixed(newObject, graph.add(write)); + } + valuePos++; + } + } else { + ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); + newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true)); + graph.addBeforeFixed(commit, newObject); + allocations[objIndex] = newObject; + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos); + if (value instanceof VirtualObjectNode) { + value = allocations[commit.getVirtualObjects().indexOf(value)]; + } + if (value == null) { + omittedValues.set(valuePos); + } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { + // Constant.illegal is always the defaultForKind, so it is skipped + Kind componentKind = element.getKind(); + Kind accessKind; + Kind valueKind = value.kind(); + if (valueKind.getStackKind() != componentKind.getStackKind()) { + // Given how Truffle uses unsafe, it can happen that + // valueKind is Kind.Int + // assert valueKind == Kind.Long || valueKind == Kind.Double; + accessKind = valueKind; + } else { + accessKind = componentKind; + } + + int scale = getScalingFactor(componentKind); + ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph); + BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; + WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object); + graph.addAfterFixed(newObject, graph.add(write)); + } + valuePos++; + } + } + } + valuePos = 0; + + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + ValueNode newObject = allocations[objIndex]; + if (virtual instanceof VirtualInstanceNode) { + for (int i = 0; i < entryCount; i++) { + if (omittedValues.get(valuePos)) { + ValueNode value = commit.getValues().get(valuePos); + assert value instanceof VirtualObjectNode; + ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; + if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { + VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; + assert virtualInstance.field(i).getKind() == Kind.Object; + WriteNode write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), + BarrierType.IMPRECISE, true); + graph.addBeforeFixed(commit, graph.add(write)); + } + } + valuePos++; + } + } else { + ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); + for (int i = 0; i < entryCount; i++) { + if (omittedValues.get(valuePos)) { + ValueNode value = commit.getValues().get(valuePos); + assert value instanceof VirtualObjectNode; + ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; + if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { + assert allocValue.kind() == Kind.Object; + WriteNode write = new WriteNode(newObject, allocValue, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, + true); + graph.addBeforeFixed(commit, graph.add(write)); + } + } + valuePos++; + } + } + } + + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex])); + allocations[objIndex] = anchor; + graph.addBeforeFixed(commit, anchor); + } + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + for (int lockDepth : commit.getLocks().get(objIndex)) { + MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth)); + graph.addBeforeFixed(commit, enter); + enter.lower(tool); + } + } + for (Node usage : commit.usages().snapshot()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject()); + graph.replaceFloating(addObject, allocations[index]); + } + graph.removeFixed(commit); + } + } else if (n instanceof OSRStartNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + OSRStartNode osrStart = (OSRStartNode) n; + StartNode newStart = graph.add(new StartNode()); + LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind))); + ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer)); + migrationEnd.setStateAfter(osrStart.stateAfter()); + + newStart.setNext(migrationEnd); + FixedNode next = osrStart.next(); + osrStart.setNext(null); + migrationEnd.setNext(next); + graph.setStart(newStart); + + // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) + int localsOffset = (graph.method().getMaxLocals() - 1) * 8; + for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { + int size = FrameStateBuilder.stackSlots(osrLocal.kind()); + int offset = localsOffset - (osrLocal.index() + size - 1) * 8; + IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1); + ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false)); + osrLocal.replaceAndDelete(load); + graph.addBeforeFixed(migrationEnd, load); + } + osrStart.replaceAtUsages(newStart); + osrStart.safeDelete(); + } + } else if (n instanceof DynamicCounterNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + BenchmarkCounters.lower((DynamicCounterNode) n, registers, runtime.getConfig(), wordKind); + } + } else if (n instanceof CheckCastDynamicNode) { + checkcastDynamicSnippets.lower((CheckCastDynamicNode) n); + } else if (n instanceof InstanceOfNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + instanceofSnippets.lower((InstanceOfNode) n, tool); + } + } else if (n instanceof InstanceOfDynamicNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + instanceofSnippets.lower((InstanceOfDynamicNode) n, tool); + } + } else if (n instanceof NewInstanceNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + newObjectSnippets.lower((NewInstanceNode) n, registers); + } + } else if (n instanceof NewArrayNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + newObjectSnippets.lower((NewArrayNode) n, registers); + } + } else if (n instanceof DynamicNewArrayNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + newObjectSnippets.lower((DynamicNewArrayNode) n, registers); + } + } else if (n instanceof MonitorEnterNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + monitorSnippets.lower((MonitorEnterNode) n, registers); + } + } else if (n instanceof MonitorExitNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + monitorSnippets.lower((MonitorExitNode) n, tool); + } + } else if (n instanceof G1PreWriteBarrier) { + writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers); + } else if (n instanceof G1PostWriteBarrier) { + writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers); + } else if (n instanceof G1ReferentFieldReadBarrier) { + writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers); + } else if (n instanceof SerialWriteBarrier) { + writeBarrierSnippets.lower((SerialWriteBarrier) n); + } else if (n instanceof SerialArrayRangeWriteBarrier) { + writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n); + } else if (n instanceof G1ArrayRangePreWriteBarrier) { + writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers); + } else if (n instanceof G1ArrayRangePostWriteBarrier) { + writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers); + } else if (n instanceof NewMultiArrayNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + newObjectSnippets.lower((NewMultiArrayNode) n); + } + } else if (n instanceof LoadExceptionObjectNode) { + exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers); + } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) { + // Nothing to do for division nodes. The HotSpot signal handler catches divisions by + // zero and the MIN_VALUE / -1 cases. + } else if (n instanceof BoxNode) { + boxingSnippets.lower((BoxNode) n, tool); + } else if (n instanceof UnboxNode) { + boxingSnippets.lower((UnboxNode) n, tool); + } else { + assert false : "Node implementing Lowerable not handled: " + n; + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static LocationNode createLocation(UnsafeAccessNode access) { + ValueNode offset = access.offset(); + if (offset.isConstant()) { + long offsetValue = offset.asConstant().asLong(); + return ConstantLocationNode.create(access.getLocationIdentity(), access.accessKind(), offsetValue, access.graph()); + } + + long displacement = 0; + int indexScaling = 1; + if (offset instanceof IntegerAddNode) { + IntegerAddNode integerAddNode = (IntegerAddNode) offset; + if (integerAddNode.y() instanceof ConstantNode) { + displacement = integerAddNode.y().asConstant().asLong(); + offset = integerAddNode.x(); + } + } + + if (offset instanceof LeftShiftNode) { + LeftShiftNode leftShiftNode = (LeftShiftNode) offset; + if (leftShiftNode.y() instanceof ConstantNode) { + long shift = leftShiftNode.y().asConstant().asLong(); + if (shift >= 1 && shift <= 3) { + if (shift == 1) { + indexScaling = 2; + } else if (shift == 2) { + indexScaling = 4; + } else { + indexScaling = 8; + } + offset = leftShiftNode.x(); + } + } + } + + return IndexedLocationNode.create(access.getLocationIdentity(), access.accessKind(), displacement, offset, access.graph(), indexScaling); + } + + private static boolean addReadBarrier(UnsafeLoadNode load) { + if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object && + !ObjectStamp.isObjectAlwaysNull(load.object())) { + ResolvedJavaType type = ObjectStamp.typeOrNull(load.object()); + if (type != null && !type.isArray()) { + return true; + } + } + return false; + } + + private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; + assert !hsMethod.getDeclaringClass().isInterface(); + assert hsMethod.isInVirtualMethodTable(); + + int vtableEntryOffset = hsMethod.vtableEntryOffset(); + assert vtableEntryOffset > 0; + // We use LocationNode.ANY_LOCATION for the reads that access the vtable + // entry as HotSpot does not guarantee that this is a final value. + ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false)); + return metaspaceMethod; + } + + private FloatingReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) { + HotSpotVMConfig config = runtime.getConfig(); + LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph); + assert !object.isConstant() || object.asConstant().isNull(); + return graph.unique(new FloatingReadNode(object, location, null, StampFactory.forKind(wordKind), guard, BarrierType.NONE, config.useCompressedClassPointers)); + } + + private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) { + HotSpotVMConfig config = runtime.getConfig(); + LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph); + assert !object.isConstant() || object.asConstant().isNull(); + return graph.add(new WriteNode(object, value, location, BarrierType.NONE, config.useCompressedClassPointers)); + } + + private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) { + BarrierType barrierType = BarrierType.NONE; + if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) { + barrierType = BarrierType.PRECISE; + } + return barrierType; + } + + private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) { + BarrierType barrierType = BarrierType.NONE; + if (storeField.field().getKind() == Kind.Object) { + barrierType = BarrierType.IMPRECISE; + } + return barrierType; + } + + private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) { + BarrierType barrierType = BarrierType.NONE; + if (store.elementKind() == Kind.Object) { + barrierType = BarrierType.PRECISE; + } + return barrierType; + } + + private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) { + BarrierType barrierType = BarrierType.NONE; + if (store.value().kind() == Kind.Object) { + ResolvedJavaType type = ObjectStamp.typeOrNull(store.object()); + if (type != null && !type.isArray()) { + barrierType = BarrierType.IMPRECISE; + } else { + barrierType = BarrierType.PRECISE; + } + } + return barrierType; + } + + private static BarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) { + BarrierType barrierType = BarrierType.NONE; + if (cas.expected().kind() == Kind.Object) { + ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object()); + if (type != null && !type.isArray()) { + barrierType = BarrierType.IMPRECISE; + } else { + barrierType = BarrierType.PRECISE; + } + } + return barrierType; + } + + protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) { + LocationIdentity loc = initialization ? INIT_LOCATION : field; + return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph); + } + + public int getScalingFactor(Kind kind) { + if (useCompressedOops() && kind == Kind.Object) { + return this.runtime.getTarget().arch.getSizeInBytes(Kind.Int); + } else { + return this.runtime.getTarget().arch.getSizeInBytes(kind); + } + } + + protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) { + LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind); + int scale = getScalingFactor(elementKind); + return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale); + } + + @Override + public ValueNode reconstructArrayIndex(LocationNode location) { + Kind elementKind = location.getValueKind(); + assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind)); + + long base; + ValueNode index; + int scale = getScalingFactor(elementKind); + + if (location instanceof ConstantLocationNode) { + base = ((ConstantLocationNode) location).getDisplacement(); + index = null; + } else if (location instanceof IndexedLocationNode) { + IndexedLocationNode indexedLocation = (IndexedLocationNode) location; + assert indexedLocation.getIndexScaling() == scale; + base = indexedLocation.getDisplacement(); + index = indexedLocation.getIndex(); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + + base -= getArrayBaseOffset(elementKind); + assert base >= 0 && base % scale == 0; + + base /= scale; + assert NumUtil.isInt(base); + + StructuredGraph graph = location.graph(); + if (index == null) { + return ConstantNode.forInt((int) base, graph); + } else { + if (base == 0) { + return index; + } else { + return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index); + } + } + } + + private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { + StructuredGraph g = n.graph(); + ValueNode array = n.array(); + ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection()); + if (arrayLength == null) { + Stamp stamp = StampFactory.positiveInt(); + ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false)); + g.addBeforeFixed(n, readArrayLength); + tool.createNullCheckGuard(readArrayLength, array); + arrayLength = readArrayLength; + } + + return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); + } + +} diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java Wed Nov 20 15:58:58 2013 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; @@ -41,7 +42,7 @@ @Override public void generate(LIRGeneratorTool gen) { - Register rawThread = runtime().getHostProviders().getRegisters().getThreadRegister(); + Register rawThread = ((HotSpotLIRGenerator) gen).getProviders().getRegisters().getThreadRegister(); gen.setResult(this, rawThread.asValue(this.kind())); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Wed Nov 20 15:58:58 2013 +0100 @@ -202,16 +202,6 @@ } @Fold - public static Register threadRegister() { - return runtime().getHostProviders().getRegisters().getThreadRegister(); - } - - @Fold - public static Register stackPointerRegister() { - return runtime().getHostProviders().getRegisters().getStackPointerRegister(); - } - - @Fold public static int wordSize() { return runtime().getTarget().wordSize; } @@ -469,23 +459,19 @@ @NodeIntrinsic(ForeignCallNode.class) private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); - /** - * Gets the value of the stack pointer register as a Word. - */ - public static Word stackPointer() { - return registerAsWord(stackPointerRegister(), true, false); + public static Word loadWordFromObject(Object object, int offset) { + assert offset != hubOffset() : "Use loadHubIntrinsic instead"; + return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION); } /** - * Gets the value of the thread register as a Word. + * Reads the value of a given register. + * + * @param register a register which must not be available to the register allocator + * @return the value of {@code register} as a word */ - public static Word thread() { - return registerAsWord(threadRegister(), true, false); - } - - public static Word loadWordFromObject(Object object, int offset) { - assert offset != hubOffset() : "Use loadHubIntrinsic instead"; - return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION); + public static Word registerAsWord(@ConstantNodeParameter Register register) { + return registerAsWord(register, true, false); } @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Wed Nov 20 15:58:58 2013 +0100 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; @@ -51,8 +52,8 @@ private static final boolean USE_C_RUNTIME = Boolean.getBoolean("graal.loadExceptionObject.useCRuntime"); @Snippet - public static Object loadException() { - Word thread = thread(); + public static Object loadException(@ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); Object exception = readExceptionOop(thread); writeExceptionOop(thread, null); writeExceptionPc(thread, Word.zero()); @@ -67,10 +68,9 @@ super(providers, target); } - public void lower(LoadExceptionObjectNode loadExceptionObject) { + public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersProvider registers) { if (USE_C_RUNTIME) { StructuredGraph graph = loadExceptionObject.graph(); - HotSpotRegistersProvider registers = ((HotSpotProviders) providers).getRegisters(); ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), true, false)); graph.addBeforeFixed(loadExceptionObject, thread); ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(providers.getForeignCalls(), LOAD_AND_CLEAR_EXCEPTION, thread)); @@ -78,6 +78,7 @@ graph.replaceFixedWithFixed(loadExceptionObject, loadExceptionC); } else { Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage()); + args.addConst("threadRegister", registers.getThreadRegister()); template(args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args); } } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Nov 20 15:58:58 2013 +0100 @@ -38,6 +38,7 @@ import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.debug.*; @@ -96,7 +97,8 @@ public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced"); @Snippet - public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { + public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister, + @ConstantParameter boolean trace) { verifyOop(object); if (object == null) { @@ -130,7 +132,7 @@ // whether the bias owner and the epoch are both still current. Word hub = loadHubIntrinsic(object, getWordKind(), anchorNode); final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - final Word thread = thread(); + final Word thread = registerAsWord(threadRegister); final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); trace(trace, " thread: 0x%016lx\n", thread); @@ -253,7 +255,7 @@ // assuming both the stack pointer and page_size have their least // significant 2 bits cleared and page_size is a power of 2 final Word alignedMask = Word.unsigned(wordSize() - 1); - final Word stackPointer = stackPointer(); + final Word stackPointer = registerAsWord(stackPointerRegister); if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) { // Most likely not a recursive lock, go into a slow runtime call traceObject(trace, "+lock{stub:failed-cas}", object, true); @@ -420,7 +422,7 @@ this.useFastLocking = useFastLocking; } - public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(MonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers) { StructuredGraph graph = monitorenterNode.graph(); checkBalancedMonitors(graph); FrameState stateAfter = monitorenterNode.stateAfter(); @@ -434,6 +436,8 @@ args.add("object", monitorenterNode.object()); args.addConst("lockDepth", monitorenterNode.getLockDepth()); boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("stackPointerRegister", registers.getStackPointerRegister()); args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod); Map nodes = template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Nov 20 15:58:58 2013 +0100 @@ -113,9 +113,10 @@ } @Snippet - public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) { + public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, + @ConstantParameter String typeContext) { Object result; - Word thread = thread(); + Word thread = registerAsWord(threadRegister); Word top = readTlabTop(thread); Word end = readTlabEnd(thread); Word newTop = top.add(size); @@ -137,19 +138,20 @@ @Snippet public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, - @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) { + @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) { if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { // This handles both negative array sizes and very large array sizes DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } - return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, typeContext); + return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, typeContext); } - private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, String typeContext) { + private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, @ConstantParameter Register threadRegister, + String typeContext) { Object result; int alignment = wordSize(); int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); - Word thread = thread(); + Word thread = registerAsWord(threadRegister); Word top = readTlabTop(thread); Word end = readTlabEnd(thread); Word newTop = top.add(allocationSize); @@ -171,7 +173,7 @@ public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType, int length); @Snippet - public static Object allocateArrayDynamic(Class elementType, int length, @ConstantParameter boolean fillContents) { + public static Object allocateArrayDynamic(Class elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) { Word hub = loadWordFromObject(elementType, arrayKlassOffset()); if (hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length); @@ -195,7 +197,7 @@ int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, "dynamic type"); + return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, "dynamic type"); } /** @@ -288,7 +290,7 @@ /** * Lowers a {@link NewInstanceNode}. */ - public void lower(NewInstanceNode newInstanceNode) { + public void lower(NewInstanceNode newInstanceNode, HotSpotRegistersProvider registers) { StructuredGraph graph = newInstanceNode.graph(); HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass(); assert !type.isArray(); @@ -300,6 +302,7 @@ args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("fillContents", newInstanceNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(type, false) : ""); SnippetTemplate template = template(args); @@ -310,14 +313,14 @@ /** * Lowers a {@link NewArrayNode}. */ - public void lower(NewArrayNode newArrayNode) { + public void lower(NewArrayNode newArrayNode, HotSpotRegistersProvider registers) { StructuredGraph graph = newArrayNode.graph(); ResolvedJavaType elementType = newArrayNode.elementType(); HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass(); Kind elementKind = elementType.getKind(); ConstantNode hub = ConstantNode.forConstant(arrayType.klass(), providers.getMetaAccess(), graph); final int headerSize = HotSpotGraalRuntime.getArrayBaseOffset(elementKind); - HotSpotHostLoweringProvider lowerer = (HotSpotHostLoweringProvider) providers.getLowerer(); + HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer(); int log2ElementSize = CodeUtil.log2(lowerer.getScalingFactor(elementKind)); Arguments args = new Arguments(allocateArray, graph.getGuardsStage()); @@ -327,6 +330,7 @@ args.addConst("headerSize", headerSize); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(arrayType, false) : ""); SnippetTemplate template = template(args); @@ -334,11 +338,12 @@ template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); } - public void lower(DynamicNewArrayNode newArrayNode) { + public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers) { Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage()); args.add("elementType", newArrayNode.getElementType()); args.add("length", newArrayNode.length()); args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); SnippetTemplate template = template(args); template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Wed Nov 20 15:58:58 2013 +0100 @@ -31,11 +31,11 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; @@ -106,11 +106,11 @@ @Snippet public static void g1PreWriteBarrier(Object object, Object expectedObject, Object location, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck, - @ConstantParameter boolean trace) { + @ConstantParameter Register threadRegister, @ConstantParameter boolean trace) { if (nullCheck && object == null) { DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); } - Word thread = thread(); + Word thread = registerAsWord(threadRegister); Object fixedObject = FixedValueAnchorNode.getObject(object); verifyOop(fixedObject); Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject); @@ -161,8 +161,9 @@ } @Snippet - public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter boolean trace) { - Word thread = thread(); + public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter Register threadRegister, + @ConstantParameter boolean trace) { + Word thread = registerAsWord(threadRegister); Object fixedObject = FixedValueAnchorNode.getObject(object); Object fixedValue = FixedValueAnchorNode.getObject(value); verifyOop(fixedObject); @@ -233,8 +234,8 @@ } @Snippet - public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length) { - Word thread = thread(); + public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); byte markingValue = thread.readByte(g1SATBQueueMarkingOffset()); // If the concurrent marker is not enabled or the vector length is zero, return. if (markingValue == (byte) 0 || length == 0) { @@ -267,12 +268,12 @@ } @Snippet - public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length) { + public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) { if (length == 0) { return; } Object dest = FixedValueAnchorNode.getObject(object); - Word thread = thread(); + Word thread = registerAsWord(threadRegister); Word bufferAddress = thread.readWord(g1CardQueueBufferOffset()); Word indexAddress = thread.add(g1CardQueueIndexOffset()); long indexValue = thread.readWord(g1CardQueueIndexOffset()).rawValue(); @@ -332,7 +333,7 @@ super(providers, target); } - public void lower(SerialWriteBarrier writeBarrier, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(SerialWriteBarrier writeBarrier) { if (writeBarrier.alwaysNull()) { writeBarrier.graph().removeFixed(writeBarrier); return; @@ -344,7 +345,7 @@ template(args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args); } - public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier) { Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage()); args.add("object", arrayRangeWriteBarrier.getObject()); args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); @@ -352,29 +353,31 @@ template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } - public void lower(G1PreWriteBarrier writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers) { Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage()); args.add("object", writeBarrierPre.getObject()); args.add("expectedObject", writeBarrierPre.getExpectedObject()); args.add("location", writeBarrierPre.getLocation()); args.addConst("doLoad", writeBarrierPre.doLoad()); args.addConst("nullCheck", writeBarrierPre.getNullCheck()); + args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("trace", traceBarrier()); template(args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args); } - public void lower(G1ReferentFieldReadBarrier readBarrier, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers) { Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage()); args.add("object", readBarrier.getObject()); args.add("expectedObject", readBarrier.getExpectedObject()); args.add("location", readBarrier.getLocation()); args.addConst("doLoad", readBarrier.doLoad()); args.addConst("nullCheck", false); + args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("trace", traceBarrier()); template(args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args); } - public void lower(G1PostWriteBarrier writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers) { if (writeBarrierPost.alwaysNull()) { writeBarrierPost.graph().removeFixed(writeBarrierPost); return; @@ -384,23 +387,26 @@ args.add("value", writeBarrierPost.getValue()); args.add("location", writeBarrierPost.getLocation()); args.addConst("usePrecise", writeBarrierPost.usePrecise()); + args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("trace", traceBarrier()); template(args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args); } - public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers) { Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage()); args.add("object", arrayRangeWriteBarrier.getObject()); args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("threadRegister", registers.getThreadRegister()); template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } - public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers) { Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage()); args.add("object", arrayRangeWriteBarrier.getObject()); args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("threadRegister", registers.getThreadRegister()); template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Wed Nov 20 15:58:58 2013 +0100 @@ -35,7 +35,7 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.word.*; /** @@ -62,12 +62,19 @@ return false; } + @Override + protected Object getConstantParameterValue(int index, String name) { + assert index == 2; + return providers.getRegisters().getThreadRegister(); + } + @Snippet - private static void exceptionHandler(Object exception, Word exceptionPc) { - checkNoExceptionInThread(assertionsEnabled()); + private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); + checkNoExceptionInThread(thread, assertionsEnabled()); checkExceptionNotNull(assertionsEnabled(), exception); - writeExceptionOop(thread(), exception); - writeExceptionPc(thread(), exceptionPc); + writeExceptionOop(thread, exception); + writeExceptionPc(thread, exceptionPc); if (logging()) { printf("handling exception %p (", Word.fromObject(exception).rawValue()); decipher(Word.fromObject(exception).rawValue()); @@ -79,7 +86,7 @@ // patch throwing pc into return address so that deoptimization finds the right debug info patchReturnAddress(exceptionPc); - Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread()); + Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread); if (logging()) { printf("handler for exception %p at %p is at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue()); @@ -91,16 +98,16 @@ patchReturnAddress(handlerPc); } - static void checkNoExceptionInThread(boolean enabled) { + static void checkNoExceptionInThread(Word thread, boolean enabled) { if (enabled) { - Object currentException = readExceptionOop(thread()); + Object currentException = readExceptionOop(thread); if (currentException != null) { fatal("exception object in thread must be null, not %p", Word.fromObject(currentException).rawValue()); } if (cAssertionsEnabled()) { // This thread-local is only cleared in DEBUG builds of the VM // (see OptoRuntime::generate_exception_blob) - Word currentExceptionPc = readExceptionPc(thread()); + Word currentExceptionPc = readExceptionPc(thread); if (currentExceptionPc.notEqual(Word.zero())) { fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Nov 20 15:58:58 2013 +0100 @@ -54,8 +54,8 @@ * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow * paths, we don't want to force the register allocator to spill around the call. As such, this stub * saves and restores all allocatable registers. It also - * {@linkplain StubUtil#handlePendingException(boolean) handles} any exceptions raised during the - * foreign call. + * {@linkplain StubUtil#handlePendingException(Word, boolean) handles} any exceptions raised during + * the foreign call. */ public class ForeignCallStub extends Stub { @@ -226,9 +226,9 @@ LocalNode[] locals = createLocals(builder, args); List invokes = new ArrayList<>(3); - ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), true, false)) : null; + ReadRegisterNode thread = builder.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), true, false)); ValueNode result = createTargetCall(builder, locals, thread); - invokes.add(createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph))); + invokes.add(createInvoke(builder, StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, builder.graph))); if (isObjectResult) { InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); result = createInvoke(builder, StubUtil.class, "verifyObject", object); @@ -276,7 +276,7 @@ return locals; } - private InvokeNode createInvoke(GraphBuilder builder, Class declaringClass, String name, ValueNode... hpeArgs) { + private InvokeNode createInvoke(GraphBuilder builder, Class declaringClass, String name, ValueNode... args) { ResolvedJavaMethod method = null; for (Method m : declaringClass.getDeclaredMethods()) { if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) { @@ -285,12 +285,25 @@ } } assert method != null : "did not find method in " + declaringClass + " named " + name; - JavaType returnType = method.getSignature().getReturnType(null); - MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType)); + Signature signature = method.getSignature(); + JavaType returnType = signature.getReturnType(null); + assert checkArgs(method, args); + MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, args, returnType)); InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI)); return invoke; } + private boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) { + Signature signature = method.getSignature(); + assert signature.getParameterCount(false) == args.length : target + ": wrong number of arguments to " + method; + for (int i = 0; i != args.length; i++) { + Kind expected = signature.getParameterKind(i).getStackKind(); + Kind actual = args[i].stamp().kind(); + assert expected == actual : target + ": wrong kind of value for argument " + i + " of calls to " + method + " [" + actual + " != " + expected + "]"; + } + return true; + } + private StubForeignCallNode createTargetCall(GraphBuilder builder, LocalNode[] locals, ReadRegisterNode thread) { if (prependThread) { ValueNode[] targetArguments = new ValueNode[1 + locals.length]; diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Wed Nov 20 15:58:58 2013 +0100 @@ -70,6 +70,7 @@ args.add("hub", null); args.add("length", null); args.addConst("intArrayHub", intArrayHub); + args.addConst("threadRegister", providers.getRegisters().getThreadRegister()); return args; } @@ -87,7 +88,7 @@ * @param intArrayHub the hub for {@code int[].class} */ @Snippet - private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub) { + private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub, @ConstantParameter Register threadRegister) { int layoutHelper = hub.readInt(layoutHelperOffset(), LocationIdentity.FINAL_LOCATION); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); @@ -101,8 +102,9 @@ } // check that array length is small enough for fast path. + Word thread = registerAsWord(threadRegister); if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) { - Word memory = refillAllocate(intArrayHub, sizeInBytes, logging()); + Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { if (logging()) { printf("newArray: allocated new array at %p\n", memory.rawValue()); @@ -114,9 +116,9 @@ printf("newArray: calling new_array_c\n"); } - newArrayC(NEW_ARRAY_C, thread(), hub, length); - handlePendingException(true); - return verifyObject(getAndClearObjectResult(thread())); + newArrayC(NEW_ARRAY_C, thread, hub, length); + handlePendingException(thread, true); + return verifyObject(getAndClearObjectResult(thread)); } public static final ForeignCallDescriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC"); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Wed Nov 20 15:58:58 2013 +0100 @@ -70,11 +70,11 @@ Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS); args.add("hub", null); args.addConst("intArrayHub", intArrayHub); + args.addConst("threadRegister", providers.getRegisters().getThreadRegister()); return args; } - private static Word allocate(int size) { - Word thread = thread(); + private static Word allocate(Word thread, int size) { Word top = readTlabTop(thread); Word end = readTlabEnd(thread); Word newTop = top.add(size); @@ -102,11 +102,12 @@ * @param intArrayHub the hub for {@code int[].class} */ @Snippet - private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub) { + private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub, @ConstantParameter Register threadRegister) { int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), LocationIdentity.FINAL_LOCATION); + Word thread = registerAsWord(threadRegister); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { if (hub.readByte(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) { - Word memory = refillAllocate(intArrayHub, sizeInBytes, logging()); + Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); initializeObjectHeader(memory, prototypeMarkWord, hub); @@ -122,9 +123,9 @@ printf("newInstance: calling new_instance_c\n"); } - newInstanceC(NEW_INSTANCE_C, thread(), hub); - handlePendingException(true); - return verifyObject(getAndClearObjectResult(thread())); + newInstanceC(NEW_INSTANCE_C, thread, hub); + handlePendingException(thread, true); + return verifyObject(getAndClearObjectResult(thread)); } /** @@ -133,10 +134,11 @@ * @param intArrayHub the hub for {@code int[].class} * @param sizeInBytes the size of the allocation * @param log specifies if logging is enabled + * * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the * operation was unsuccessful */ - static Word refillAllocate(Word intArrayHub, int sizeInBytes, boolean log) { + static Word refillAllocate(Word thread, Word intArrayHub, int sizeInBytes, boolean log) { // If G1 is enabled, the "eden" allocation space is not the same always // and therefore we have to go to slowpath to allocate a new TLAB. if (useG1GC()) { @@ -148,7 +150,6 @@ Word intArrayMarkWord = Word.unsigned(tlabIntArrayMarkWord()); int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize(); - Word thread = thread(); Word top = readTlabTop(thread); Word end = readTlabEnd(thread); @@ -206,7 +207,7 @@ end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes)); initializeTlab(thread, top, end); - return NewInstanceStub.allocate(sizeInBytes); + return NewInstanceStub.allocate(thread, sizeInBytes); } else { return Word.zero(); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Wed Nov 20 15:58:58 2013 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; @@ -82,11 +83,21 @@ protected Arguments makeArguments(SnippetInfo stub) { Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS); for (int i = 0; i < stub.getParameterCount(); i++) { - args.add(stub.getParameterName(i), null); + String name = stub.getParameterName(i); + if (stub.isConstantParameter(i)) { + args.addConst(name, getConstantParameterValue(i, name)); + } else { + assert !stub.isVarargsParameter(i); + args.add(name, null); + } } return args; } + protected Object getConstantParameterValue(int index, String name) { + throw new GraalInternalError("%s must override getConstantParameterValue() to provide a value for parameter %d%s", getClass().getName(), index, name == null ? "" : " (" + name + ")"); + } + @Override protected Object debugScopeContext() { return getInstalledCodeOwner(); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Wed Nov 20 15:58:58 2013 +0100 @@ -73,10 +73,10 @@ return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes); } - public static void handlePendingException(boolean isObjectResult) { - if (clearPendingException(thread())) { + public static void handlePendingException(Word thread, boolean isObjectResult) { + if (clearPendingException(thread)) { if (isObjectResult) { - getAndClearObjectResult(thread()); + getAndClearObjectResult(thread); } DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); } diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java Wed Nov 20 15:58:58 2013 +0100 @@ -36,7 +36,7 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.word.*; /** @@ -58,8 +58,14 @@ return false; } + @Override + protected Object getConstantParameterValue(int index, String name) { + assert index == 2; + return providers.getRegisters().getThreadRegister(); + } + @Snippet - private static void unwindExceptionToCaller(Object exception, Word returnAddress) { + private static void unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister) { Pointer exceptionOop = Word.fromObject(exception); if (logging()) { printf("unwinding exception %p (", exceptionOop.rawValue()); @@ -68,10 +74,11 @@ decipher(returnAddress.rawValue()); printf(")\n"); } - checkNoExceptionInThread(assertionsEnabled()); + Word thread = registerAsWord(threadRegister); + checkNoExceptionInThread(thread, assertionsEnabled()); checkExceptionNotNull(assertionsEnabled(), exception); - Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread(), returnAddress); + Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread, returnAddress); if (logging()) { printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue()); diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Wed Nov 20 15:58:58 2013 +0100 @@ -34,7 +34,9 @@ import com.oracle.graal.asm.amd64.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.StandardOp.NullCheck; import com.oracle.graal.lir.asm.*; public class AMD64Move { @@ -93,7 +95,7 @@ } } - public abstract static class MemOp extends AMD64LIRInstruction { + public abstract static class MemOp extends AMD64LIRInstruction implements ImplicitNullCheck { protected final Kind kind; @Use({COMPOSITE}) protected AMD64AddressValue address; @@ -114,6 +116,14 @@ } emitMemAccess(masm); } + + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && value.equals(address.base) && address.index == Value.ILLEGAL && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) { + state = nullCheckState; + return true; + } + return false; + } } public static class LoadOp extends MemOp { @@ -295,7 +305,7 @@ } } - public static class NullCheckOp extends AMD64LIRInstruction { + public static class NullCheckOp extends AMD64LIRInstruction implements NullCheck { @Use({REG}) protected AllocatableValue input; @State protected LIRFrameState state; @@ -310,6 +320,14 @@ tasm.recordImplicitException(masm.codeBuffer.position(), state); masm.nullCheck(asRegister(input)); } + + public Value getCheckedValue() { + return input; + } + + public LIRFrameState getState() { + return state; + } } @Opcode("CAS") diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Wed Nov 20 15:58:58 2013 +0100 @@ -32,7 +32,9 @@ import com.oracle.graal.asm.sparc.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.StandardOp.NullCheck; import com.oracle.graal.lir.asm.*; public class SPARCMove { @@ -91,7 +93,7 @@ } } - public abstract static class MemOp extends SPARCLIRInstruction { + public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck { protected final Kind kind; @Use({COMPOSITE}) protected SPARCAddressValue address; @@ -112,6 +114,14 @@ } emitMemAccess(masm); } + + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && value.equals(address.base) && address.index == Value.ILLEGAL && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) { + state = nullCheckState; + return true; + } + return false; + } } public static class LoadOp extends MemOp { @@ -193,7 +203,7 @@ } } - public static class NullCheckOp extends SPARCLIRInstruction { + public static class NullCheckOp extends SPARCLIRInstruction implements NullCheck { @Use({REG}) protected AllocatableValue input; @State protected LIRFrameState state; @@ -208,6 +218,14 @@ tasm.recordImplicitException(masm.codeBuffer.position(), state); new Ldx(new SPARCAddress(asRegister(input), 0), r0).emit(masm); } + + public Value getCheckedValue() { + return input; + } + + public LIRFrameState getState() { + return state; + } } @Opcode("CAS") diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java Wed Nov 20 15:58:58 2013 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 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 com.oracle.graal.lir; + +import java.util.*; + +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.StandardOp.NullCheck; +import com.oracle.graal.nodes.cfg.*; + +public final class NullCheckOptimizer { + + public static void optimize(LIR ir, int implicitNullCheckLimit) { + List blocks = ir.codeEmittingOrder(); + NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit); + } + + private NullCheckOptimizer() { + } + + private static void foldNullChecks(LIR ir, List blocks, int implicitNullCheckLimit) { + for (Block block : blocks) { + List list = ir.lir(block); + + if (!list.isEmpty()) { + + LIRInstruction lastInstruction = list.get(0); + for (int i = 0; i < list.size(); i++) { + LIRInstruction instruction = list.get(i); + + if (instruction instanceof ImplicitNullCheck && lastInstruction instanceof NullCheck) { + NullCheck nullCheck = (NullCheck) lastInstruction; + ImplicitNullCheck implicitNullCheck = (ImplicitNullCheck) instruction; + if (implicitNullCheck.makeNullCheckFor(nullCheck.getCheckedValue(), nullCheck.getState(), implicitNullCheckLimit)) { + list.remove(i - 1); + if (i < list.size()) { + instruction = list.get(i); + } + } + } + lastInstruction = instruction; + } + } + } + } +} diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Wed Nov 20 15:58:58 2013 +0100 @@ -51,6 +51,16 @@ void setFallThroughTarget(LabelRef target); } + public interface NullCheck { + Value getCheckedValue(); + + LIRFrameState getState(); + } + + public interface ImplicitNullCheck { + boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit); + } + /** * LIR operation that defines the position of a label. The first operation of every block must * implement this interface. diff -r ec3e4f35e466 -r 514e809bd97d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Wed Nov 20 15:58:23 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Wed Nov 20 15:58:58 2013 +0100 @@ -56,6 +56,7 @@ public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) { super(StampFactory.forKind(kind)); + assert register != null; this.register = register; this.directUse = directUse; this.incoming = incoming; @@ -67,6 +68,7 @@ */ public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { super(StampFactory.forNodeIntrinsic()); + assert register != null; this.register = register; this.directUse = directUse; this.incoming = incoming; diff -r ec3e4f35e466 -r 514e809bd97d src/gpu/hsail/vm/hsailKernelArguments.cpp --- a/src/gpu/hsail/vm/hsailKernelArguments.cpp Wed Nov 20 15:58:23 2013 +0100 +++ b/src/gpu/hsail/vm/hsailKernelArguments.cpp Wed Nov 20 15:58:58 2013 +0100 @@ -93,7 +93,7 @@ void HSAILKernelArguments::do_int() { // The last int is the iteration variable in an IntStream, but we don't pass it // since we use the HSAIL workitemid in place of that int value - if (_index == _length) { + if (_parameter_index == _parameter_count - 1) { if (TraceGPUInteraction) { tty->print_cr("[HSAIL] HSAILKernelArguments::not pushing trailing int"); } @@ -136,17 +136,19 @@ void HSAILKernelArguments::do_object() { if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object."); + tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, _parameter_index=%d", _parameter_index); } - if (_index == _length) { - // last arg in object stream lambda is the object stream source array + oop arg = _args->obj_at(_index++); + + // check if this is last arg in signature + // an object as last parameter requires an object stream source array to be passed + if (_parameter_index == _parameter_count - 1) { if (TraceGPUInteraction) { tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref"); } + assert(arg->is_objArray(), "arg type mismatch"); } - oop arg = _args->obj_at(_index++); - assert(arg->is_array(), "arg type mismatch"); if (TraceGPUInteraction) { tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, 0x%08x is a %s", (address) arg, arg->klass()->external_name()); } @@ -157,24 +159,9 @@ void HSAILKernelArguments::do_object(int begin, int end) { if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int begin, int end)."); - } - - if ((!_is_static && (_index >=(_length-1))) || (_is_static && (_index >=(_length)))) { - // last arg in object stream lambda is the object stream source array - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref"); - } + tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int begin, int end), begin=%d, end=%d.", begin, end); } - - oop arg = _args->obj_at(_index++); - assert(arg->is_array(), "arg type mismatch"); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int, int), 0x%08x is a %s", (address) arg, arg->klass()->external_name()); - } - - bool pushed = gpu::Hsail::_okra_push_object(_kernel, arg); - assert(pushed == true, "arg push failed"); + do_object(); } void HSAILKernelArguments::do_void() { diff -r ec3e4f35e466 -r 514e809bd97d src/gpu/hsail/vm/hsailKernelArguments.hpp --- a/src/gpu/hsail/vm/hsailKernelArguments.hpp Wed Nov 20 15:58:23 2013 +0100 +++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp Wed Nov 20 15:58:58 2013 +0100 @@ -42,6 +42,8 @@ int _index; // Kernel to push into address _kernel; + // number of parameters in the signature + int _parameter_count; bool _is_static; @@ -55,8 +57,10 @@ _args = args; _kernel = kernel; _is_static = is_static; - + _length = args->length(); + _parameter_count = ArgumentCount(signature).size(); + if (TraceGPUInteraction) { tty->print_cr("[HSAIL] sig:%s args length=%d", signature->as_C_string(), _length); }