This commit is contained in:
Jesper Wilhelmsson 2017-09-03 14:19:45 +02:00
commit 6cdc8d381f
137 changed files with 2095 additions and 3599 deletions
hotspot
make/lib
src
cpu
jdk.aot/share/classes
jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat
jdk.tools.jaotc/src/jdk/tools/jaotc
jdk.internal.vm.compiler/share/classes
org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements
org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test
org.graalvm.compiler.code/src/org/graalvm/compiler/code
org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test
org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test
org.graalvm.compiler.graph/src/org/graalvm/compiler/graph
org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64
org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64
org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test
org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot
org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra
org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir
org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes
org.graalvm.compiler.printer/src/org/graalvm/compiler/printer
org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier
org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements
os
os_cpu
share/vm

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -88,11 +88,6 @@ ifneq ($(call check-jvm-feature, jvmci), true)
JVM_EXCLUDE_FILES += jvmciCodeInstaller_$(HOTSPOT_TARGET_CPU_ARCH).cpp JVM_EXCLUDE_FILES += jvmciCodeInstaller_$(HOTSPOT_TARGET_CPU_ARCH).cpp
endif endif
ifneq ($(call check-jvm-feature, fprof), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_FPROF=0
JVM_EXCLUDE_FILES += fprofiler.cpp
endif
ifneq ($(call check-jvm-feature, vm-structs), true) ifneq ($(call check-jvm-feature, vm-structs), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_VM_STRUCTS=0 JVM_CFLAGS_FEATURES += -DINCLUDE_VM_STRUCTS=0
JVM_EXCLUDE_FILES += vmStructs.cpp JVM_EXCLUDE_FILES += vmStructs.cpp

@ -3630,6 +3630,12 @@ void MacroAssembler::store_heap_oop_null(Address dst) {
} }
#if INCLUDE_ALL_GCS #if INCLUDE_ALL_GCS
/*
* g1_write_barrier_pre -- G1GC pre-write barrier for store of new_val at
* store_addr.
*
* Allocates rscratch1
*/
void MacroAssembler::g1_write_barrier_pre(Register obj, void MacroAssembler::g1_write_barrier_pre(Register obj,
Register pre_val, Register pre_val,
Register thread, Register thread,
@ -3645,10 +3651,8 @@ void MacroAssembler::g1_write_barrier_pre(Register obj,
Label done; Label done;
Label runtime; Label runtime;
assert(pre_val != noreg, "check this code"); assert_different_registers(obj, pre_val, tmp, rscratch1);
assert(pre_val != noreg && tmp != noreg, "expecting a register");
if (obj != noreg)
assert_different_registers(obj, pre_val, tmp);
Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_active())); SATBMarkQueue::byte_offset_of_active()));
@ -3722,12 +3726,22 @@ void MacroAssembler::g1_write_barrier_pre(Register obj,
bind(done); bind(done);
} }
/*
* g1_write_barrier_post -- G1GC post-write barrier for store of new_val at
* store_addr
*
* Allocates rscratch1
*/
void MacroAssembler::g1_write_barrier_post(Register store_addr, void MacroAssembler::g1_write_barrier_post(Register store_addr,
Register new_val, Register new_val,
Register thread, Register thread,
Register tmp, Register tmp,
Register tmp2) { Register tmp2) {
assert(thread == rthread, "must be"); assert(thread == rthread, "must be");
assert_different_registers(store_addr, new_val, thread, tmp, tmp2,
rscratch1);
assert(store_addr != noreg && new_val != noreg && tmp != noreg
&& tmp2 != noreg, "expecting a register");
Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
DirtyCardQueue::byte_offset_of_index())); DirtyCardQueue::byte_offset_of_index()));

@ -2067,7 +2067,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ g1_write_barrier_pre(noreg /* obj */, __ g1_write_barrier_pre(noreg /* obj */,
r0 /* pre_val */, r0 /* pre_val */,
rthread /* thread */, rthread /* thread */,
rscratch1 /* tmp */, rscratch2 /* tmp */,
true /* tosca_live */, true /* tosca_live */,
true /* expand_call */); true /* expand_call */);
} }

@ -170,7 +170,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
// G1 barrier needs uncompressed oop for region cross check. // G1 barrier needs uncompressed oop for region cross check.
Register new_val = val; Register new_val = val;
if (UseCompressedOops) { if (UseCompressedOops) {
new_val = rscratch1; new_val = rscratch2;
__ mov(new_val, val); __ mov(new_val, val);
} }
__ store_heap_oop(Address(r3, 0), val); __ store_heap_oop(Address(r3, 0), val);

@ -292,7 +292,7 @@ void MacroAssembler::verify_thread() {
if (VerifyThread) { if (VerifyThread) {
// NOTE: this chops off the heads of the 64-bit O registers. // NOTE: this chops off the heads of the 64-bit O registers.
// make sure G2_thread contains the right value // make sure G2_thread contains the right value
save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod for -Xprof) save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod)
mov(G1, L1); // avoid clobbering G1 mov(G1, L1); // avoid clobbering G1
// G2 saved below // G2 saved below
mov(G3, L3); // avoid clobbering G3 mov(G3, L3); // avoid clobbering G3
@ -398,7 +398,7 @@ void MacroAssembler::reset_last_Java_frame(void) {
#ifdef ASSERT #ifdef ASSERT
// check that it WAS previously set // check that it WAS previously set
save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame for -Xprof save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame
ld_ptr(sp_addr, L0); ld_ptr(sp_addr, L0);
tst(L0); tst(L0);
breakpoint_trap(Assembler::zero, Assembler::ptr_cc); breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
@ -618,7 +618,7 @@ void MacroAssembler::set_vm_result(Register oop_result) {
# ifdef ASSERT # ifdef ASSERT
// Check that we are not overwriting any other oop. // Check that we are not overwriting any other oop.
save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod for -Xprof save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod
ld_ptr(vm_result_addr, L0); ld_ptr(vm_result_addr, L0);
tst(L0); tst(L0);
restore(); restore();

@ -2928,7 +2928,7 @@ void TemplateTable::invokevirtual(int byte_no) {
__ br(Assembler::zero, false, Assembler::pt, notFinal); __ br(Assembler::zero, false, Assembler::pt, notFinal);
__ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters __ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters
if (RewriteBytecodes && !UseSharedSpaces) { if (RewriteBytecodes && !UseSharedSpaces && !DumpSharedSpaces) {
patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp); patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp);
} }

@ -187,11 +187,10 @@ public final class BinaryContainer implements SymbolTable {
{"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"}, {"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
{"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"}, {"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
{"StubRoutines::_unsafe_arraycopy", "_aot_stub_routines_unsafe_arraycopy"},
{"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"}, {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
{"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"}, {"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
{"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"}, {"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
{"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"}, {"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
@ -478,8 +477,8 @@ public final class BinaryContainer implements SymbolTable {
} }
/** /**
* Creates a global symbol of the form {@code "A" + container name}. * Creates a global symbol of the form {@code "A" + container name}. Note, linker on Windows
* Note, linker on Windows does not allow names which start with '.' * does not allow names which start with '.'
* *
* @param container container to create a symbol for * @param container container to create a symbol for
*/ */
@ -685,7 +684,8 @@ public final class BinaryContainer implements SymbolTable {
} }
/** /**
* Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to patch. * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
* patch.
* *
* @param oopName name of the oop symbol * @param oopName name of the oop symbol
*/ */
@ -728,10 +728,9 @@ public final class BinaryContainer implements SymbolTable {
} }
/** /**
* Add klass symbol by as follows. * Add klass symbol by as follows. - Adding the symbol name to the metaspace.names section - Add
* - Adding the symbol name to the metaspace.names section * the offset of the name in metaspace.names to metaspace.offsets - Extend the klasses.got
* - Add the offset of the name in metaspace.names to metaspace.offsets * section with another slot for the VM to patch
* - Extend the klasses.got section with another slot for the VM to patch
* *
* @param klassName name of the metaspace symbol * @param klassName name of the metaspace symbol
* @return the got offset in the klasses.got of the metaspace symbol * @return the got offset in the klasses.got of the metaspace symbol

@ -27,6 +27,8 @@ import java.util.ListIterator;
import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.GraalCompiler; import org.graalvm.compiler.core.GraalCompiler;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
@ -127,7 +129,13 @@ final class AOTBackend {
ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE); ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
final boolean isImmutablePIC = true; final boolean isImmutablePIC = true;
CompilationResult compilationResult = new CompilationResult(resolvedMethod.getName(), isImmutablePIC); CompilationIdentifier id = new CompilationIdentifier() {
@Override
public String toString(Verbosity verbosity) {
return resolvedMethod.getName();
}
};
CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(), return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
compilationResult, CompilationResultBuilderFactory.Default); compilationResult, CompilationResultBuilderFactory.Default);

@ -57,7 +57,9 @@ public @interface ClassSubstitution {
/** /**
* Determines if the substitutions are for classes that may not be part of the runtime. * Determines if the substitutions are for classes that may not be part of the runtime.
* Substitutions for such classes are omitted if the original classes cannot be found. * Substitutions for such classes are omitted if the original classes cannot be found. If
* multiple classes are specified using {@link #className()} and {@link #optional()} is false,
* then at least one of the classes is required to be reachable.
*/ */
boolean optional() default false; boolean optional() default false;
} }

@ -90,7 +90,7 @@ public abstract class AssemblerTest extends GraalTest {
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).compilationId(compilationId).build(); StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).compilationId(compilationId).build();
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention(); CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention();
CompilationResult compResult = new CompilationResult(); CompilationResult compResult = new CompilationResult(graph.compilationId());
byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc); byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
compResult.setTargetCode(targetCode, targetCode.length); compResult.setTargetCode(targetCode, targetCode.length);
compResult.setTotalFrameSize(0); compResult.setTotalFrameSize(0);

@ -33,6 +33,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.util.EconomicSet; import org.graalvm.util.EconomicSet;
@ -190,6 +191,8 @@ public class CompilationResult {
private final String name; private final String name;
private final CompilationIdentifier compilationId;
/** /**
* The buffer containing the emitted machine code. * The buffer containing the emitted machine code.
*/ */
@ -222,21 +225,26 @@ public class CompilationResult {
private boolean isImmutablePIC; private boolean isImmutablePIC;
public CompilationResult() { public CompilationResult(CompilationIdentifier compilationId) {
this(null, false); this(compilationId, compilationId.toString(CompilationIdentifier.Verbosity.NAME), false);
}
public CompilationResult(CompilationIdentifier compilationId, String name) {
this(compilationId, name, false);
}
public CompilationResult(CompilationIdentifier compilationId, boolean isImmutablePIC) {
this(compilationId, null, isImmutablePIC);
}
public CompilationResult(CompilationIdentifier compilationId, String name, boolean isImmutablePIC) {
this.compilationId = compilationId;
this.name = name;
this.isImmutablePIC = isImmutablePIC;
} }
public CompilationResult(String name) { public CompilationResult(String name) {
this(name, false); this(null, name);
}
public CompilationResult(boolean isImmutablePIC) {
this(null, isImmutablePIC);
}
public CompilationResult(String name, boolean isImmutablePIC) {
this.name = name;
this.isImmutablePIC = isImmutablePIC;
} }
@Override @Override
@ -266,6 +274,7 @@ public class CompilationResult {
this.totalFrameSize == that.totalFrameSize && this.totalFrameSize == that.totalFrameSize &&
this.targetCodeSize == that.targetCodeSize && this.targetCodeSize == that.targetCodeSize &&
Objects.equals(this.name, that.name) && Objects.equals(this.name, that.name) &&
Objects.equals(this.compilationId, that.compilationId) &&
Objects.equals(this.annotations, that.annotations) && Objects.equals(this.annotations, that.annotations) &&
Objects.equals(this.dataSection, that.dataSection) && Objects.equals(this.dataSection, that.dataSection) &&
Objects.equals(this.exceptionHandlers, that.exceptionHandlers) && Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
@ -670,6 +679,10 @@ public class CompilationResult {
return name; return name;
} }
public CompilationIdentifier getCompilationId() {
return compilationId;
}
public void setHasUnsafeAccess(boolean hasUnsafeAccess) { public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
checkOpen(); checkOpen();
this.hasUnsafeAccess = hasUnsafeAccess; this.hasUnsafeAccess = hasUnsafeAccess;

@ -949,7 +949,7 @@ public abstract class GraalCompilerTest extends GraalTest {
try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) { try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI); CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI);
CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(), id, options); CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(graphToCompile.compilationId()), id, options);
printer.finish(compResult); printer.finish(compResult);
try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult); try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult);
@ -1019,17 +1019,19 @@ public abstract class GraalCompilerTest extends GraalTest {
*/ */
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
OptionValues options = graph == null ? getInitialOptions() : graph.getOptions(); OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options); CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
} }
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) { protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) {
OptionValues options = graph == null ? getInitialOptions() : graph.getOptions(); OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
return compile(installedCodeOwner, graph, new CompilationResult(), compilationId, options); return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
} }
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, OptionValues options) { protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, OptionValues options) {
assert graph == null || graph.getOptions() == options; assert graph == null || graph.getOptions() == options;
return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options); CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
} }
/** /**

@ -64,7 +64,7 @@ public class InfopointReasonTest extends GraalCompilerTest {
final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod"); final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
final StructuredGraph graph = parseEager(method, AllowAssumptions.YES); final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(), final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default); createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
for (Infopoint sp : cr.getInfopoints()) { for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason); assertNotNull(sp.reason);
if (sp instanceof Call) { if (sp instanceof Call) {
@ -86,7 +86,7 @@ public class InfopointReasonTest extends GraalCompilerTest {
assertTrue(graphLineSPs > 0); assertTrue(graphLineSPs > 0);
PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)); PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(), final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(),
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default); createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
int lineSPs = 0; int lineSPs = 0;
for (Infopoint sp : cr.getInfopoints()) { for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason); assertNotNull(sp.reason);

@ -123,7 +123,7 @@ public class InvokeGraal {
ProfilingInfo profilingInfo = graph.getProfilingInfo(method); ProfilingInfo profilingInfo = graph.getProfilingInfo(method);
/* The default class and configuration for compilation results. */ /* The default class and configuration for compilation results. */
CompilationResult compilationResult = new CompilationResult(); CompilationResult compilationResult = new CompilationResult(graph.compilationId());
CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default; CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
/* Invoke the whole Graal compilation pipeline. */ /* Invoke the whole Graal compilation pipeline. */

@ -0,0 +1,203 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.graph.test;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeBitMap;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class NodeBitMapTest extends GraphTest {
@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
static final class TestNode extends Node {
public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
protected TestNode() {
super(TYPE);
}
}
private Graph graph;
private TestNode[] nodes = new TestNode[100];
private NodeBitMap map;
@Before
public void before() {
// Need to initialize HotSpotGraalRuntime before any Node class is initialized.
Graal.getRuntime();
OptionValues options = getOptions();
graph = new Graph(options, getDebug(options));
for (int i = 0; i < nodes.length; i++) {
nodes[i] = graph.add(new TestNode());
}
map = graph.createNodeBitMap();
}
@Test
public void iterateEmpty() {
for (Node n : map) {
Assert.fail("no elements expected: " + n);
}
}
@Test
public void iterateMarkedNodes() {
map.mark(nodes[99]);
map.mark(nodes[0]);
map.mark(nodes[7]);
map.mark(nodes[1]);
map.mark(nodes[53]);
Iterator<Node> iter = map.iterator();
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[0], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[1], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[7], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[53], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[99], iter.next());
Assert.assertFalse(iter.hasNext());
}
@Test
public void deleteNodeWhileIterating() {
map.mark(nodes[99]);
map.mark(nodes[0]);
map.mark(nodes[7]);
map.mark(nodes[1]);
map.mark(nodes[53]);
Iterator<Node> iter = map.iterator();
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[0], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[1], iter.next());
nodes[7].markDeleted();
nodes[53].markDeleted();
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[99], iter.next());
Assert.assertFalse(iter.hasNext());
}
@Test
public void deleteAllNodesBeforeIterating() {
for (int i = 0; i < nodes.length; i++) {
map.mark(nodes[i]);
nodes[i].markDeleted();
}
Iterator<Node> iter = map.iterator();
Assert.assertFalse(iter.hasNext());
}
@Test
public void multipleHasNextInvocations() {
map.mark(nodes[7]);
Iterator<Node> iter = map.iterator();
Assert.assertTrue(iter.hasNext());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[7], iter.next());
Assert.assertFalse(iter.hasNext());
}
@Test(expected = NoSuchElementException.class)
public void noSuchElement() {
map.iterator().next();
}
@Test(expected = ConcurrentModificationException.class)
public void concurrentModification() {
map.mark(nodes[7]);
map.mark(nodes[99]);
map.mark(nodes[0]);
map.mark(nodes[7]);
map.mark(nodes[1]);
map.mark(nodes[53]);
Iterator<Node> iter = map.iterator();
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[0], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[1], iter.next());
Assert.assertTrue(iter.hasNext());
nodes[7].markDeleted();
iter.next();
}
@Test
public void nextWithoutHasNext() {
map.mark(nodes[99]);
map.mark(nodes[0]);
map.mark(nodes[7]);
map.mark(nodes[1]);
map.mark(nodes[53]);
Iterator<Node> iter = map.iterator();
Assert.assertEquals(nodes[0], iter.next());
Assert.assertEquals(nodes[1], iter.next());
Assert.assertEquals(nodes[7], iter.next());
Assert.assertEquals(nodes[53], iter.next());
Assert.assertEquals(nodes[99], iter.next());
Assert.assertFalse(iter.hasNext());
}
@Test
public void markWhileIterating() {
map.mark(nodes[0]);
Iterator<Node> iter = map.iterator();
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[0], iter.next());
map.mark(nodes[7]);
Assert.assertTrue(iter.hasNext());
map.mark(nodes[1]);
Assert.assertEquals(nodes[7], iter.next());
map.mark(nodes[99]);
map.mark(nodes[53]);
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[53], iter.next());
Assert.assertTrue(iter.hasNext());
Assert.assertEquals(nodes[99], iter.next());
Assert.assertFalse(iter.hasNext());
}
}

@ -23,22 +23,23 @@
package org.graalvm.compiler.graph; package org.graalvm.compiler.graph;
import java.util.Arrays; import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.graph.iterators.NodeIterable;
public final class NodeBitMap implements NodeIterable<Node> { public final class NodeBitMap extends NodeIdAccessor implements NodeIterable<Node> {
private static final int SHIFT = 6; private static final int SHIFT = 6;
private long[] bits; private long[] bits;
private int nodeCount; private int nodeCount;
private int counter; private int counter;
private final Graph graph;
public NodeBitMap(Graph graph) { public NodeBitMap(Graph graph) {
super(graph);
this.nodeCount = graph.nodeIdCount(); this.nodeCount = graph.nodeIdCount();
this.bits = new long[sizeForNodeCount(nodeCount)]; this.bits = new long[sizeForNodeCount(nodeCount)];
this.graph = graph;
} }
private static int sizeForNodeCount(int nodeCount) { private static int sizeForNodeCount(int nodeCount) {
@ -50,9 +51,9 @@ public final class NodeBitMap implements NodeIterable<Node> {
} }
private NodeBitMap(NodeBitMap other) { private NodeBitMap(NodeBitMap other) {
super(other.graph);
this.bits = other.bits.clone(); this.bits = other.bits.clone();
this.nodeCount = other.nodeCount; this.nodeCount = other.nodeCount;
this.graph = other.graph;
} }
public Graph graph() { public Graph graph() {
@ -60,12 +61,12 @@ public final class NodeBitMap implements NodeIterable<Node> {
} }
public boolean isNew(Node node) { public boolean isNew(Node node) {
return node.id() >= nodeCount; return getNodeId(node) >= nodeCount;
} }
public boolean isMarked(Node node) { public boolean isMarked(Node node) {
assert check(node, false); assert check(node, false);
return isMarked(node.id()); return isMarked(getNodeId(node));
} }
public boolean checkAndMarkInc(Node node) { public boolean checkAndMarkInc(Node node) {
@ -84,33 +85,33 @@ public final class NodeBitMap implements NodeIterable<Node> {
public boolean isMarkedAndGrow(Node node) { public boolean isMarkedAndGrow(Node node) {
assert check(node, true); assert check(node, true);
int id = node.id(); int id = getNodeId(node);
checkGrow(id); checkGrow(id);
return isMarked(id); return isMarked(id);
} }
public void mark(Node node) { public void mark(Node node) {
assert check(node, false); assert check(node, false);
int id = node.id(); int id = getNodeId(node);
bits[id >> SHIFT] |= (1L << id); bits[id >> SHIFT] |= (1L << id);
} }
public void markAndGrow(Node node) { public void markAndGrow(Node node) {
assert check(node, true); assert check(node, true);
int id = node.id(); int id = getNodeId(node);
checkGrow(id); checkGrow(id);
bits[id >> SHIFT] |= (1L << id); bits[id >> SHIFT] |= (1L << id);
} }
public void clear(Node node) { public void clear(Node node) {
assert check(node, false); assert check(node, false);
int id = node.id(); int id = getNodeId(node);
bits[id >> SHIFT] &= ~(1L << id); bits[id >> SHIFT] &= ~(1L << id);
} }
public void clearAndGrow(Node node) { public void clearAndGrow(Node node) {
assert check(node, true); assert check(node, true);
int id = node.id(); int id = getNodeId(node);
checkGrow(id); checkGrow(id);
bits[id >> SHIFT] &= ~(1L << id); bits[id >> SHIFT] &= ~(1L << id);
} }
@ -181,15 +182,30 @@ public final class NodeBitMap implements NodeIterable<Node> {
} }
} }
protected int nextMarkedNodeId(int fromNodeId) { protected Node nextMarkedNode(int fromNodeId) {
assert fromNodeId >= 0; assert fromNodeId >= 0;
int wordIndex = fromNodeId >> SHIFT; int wordIndex = fromNodeId >> SHIFT;
int wordsInUse = bits.length; int wordsInUse = bits.length;
if (wordIndex < wordsInUse) { if (wordIndex < wordsInUse) {
long word = bits[wordIndex] & (0xFFFFFFFFFFFFFFFFL << fromNodeId); long word = getPartOfWord(bits[wordIndex], fromNodeId);
while (true) { while (true) {
if (word != 0) { while (word != 0) {
return wordIndex * Long.SIZE + Long.numberOfTrailingZeros(word); int bitIndex = Long.numberOfTrailingZeros(word);
int nodeId = wordIndex * Long.SIZE + bitIndex;
Node result = graph.getNode(nodeId);
if (result == null) {
// node was deleted -> clear the bit and continue searching
bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex);
int nextNodeId = nodeId + 1;
if ((nextNodeId & (Long.SIZE - 1)) == 0) {
// we reached the end of this word
break;
} else {
word = getPartOfWord(word, nextNodeId);
}
} else {
return result;
}
} }
if (++wordIndex == wordsInUse) { if (++wordIndex == wordsInUse) {
break; break;
@ -197,30 +213,56 @@ public final class NodeBitMap implements NodeIterable<Node> {
word = bits[wordIndex]; word = bits[wordIndex];
} }
} }
return -2; return null;
} }
private static long getPartOfWord(long word, int firstNodeIdToInclude) {
return word & (0xFFFFFFFFFFFFFFFFL << firstNodeIdToInclude);
}
/**
* This iterator only returns nodes that are marked in the {@link NodeBitMap} and are alive in
* the corresponding {@link Graph}.
*/
private class MarkedNodeIterator implements Iterator<Node> { private class MarkedNodeIterator implements Iterator<Node> {
private int nextNodeId; private int currentNodeId;
private Node currentNode;
MarkedNodeIterator() { MarkedNodeIterator() {
nextNodeId = -1; currentNodeId = -1;
forward(); forward();
} }
private void forward() { private void forward() {
nextNodeId = NodeBitMap.this.nextMarkedNodeId(nextNodeId + 1); assert currentNode == null;
currentNode = NodeBitMap.this.nextMarkedNode(currentNodeId + 1);
if (currentNode != null) {
assert currentNode.isAlive();
currentNodeId = getNodeId(currentNode);
} else {
currentNodeId = -1;
}
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return nextNodeId >= 0; if (currentNode == null && currentNodeId >= 0) {
forward();
}
return currentNodeId >= 0;
} }
@Override @Override
public Node next() { public Node next() {
Node result = graph.getNode(nextNodeId); if (!hasNext()) {
forward(); throw new NoSuchElementException();
}
if (!currentNode.isAlive()) {
throw new ConcurrentModificationException("NodeBitMap was modified between the calls to hasNext() and next()");
}
Node result = currentNode;
currentNode = null;
return result; return result;
} }

@ -1,117 +0,0 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.aarch64;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder;
import org.graalvm.compiler.core.common.type.RawPointerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Value;
@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_UNKNOWN)
public final class AArch64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
public static final NodeClass<AArch64RawNativeCallNode> TYPE = NodeClass.create(AArch64RawNativeCallNode.class);
protected final JavaConstant functionPointer;
@Input NodeInputList<ValueNode> args;
public AArch64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
super(TYPE, StampFactory.forKind(returnType));
this.functionPointer = functionPointer;
this.args = new NodeInputList<>(this, args);
}
private static class PointerType implements JavaType {
@Override
public String getName() {
return "void*";
}
@Override
public JavaType getComponentType() {
return null;
}
@Override
public JavaType getArrayClass() {
return null;
}
@Override
public JavaKind getJavaKind() {
// native pointers and java objects use the same registers in the calling convention
return JavaKind.Object;
}
@Override
public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
return null;
}
}
private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
if (stamp instanceof RawPointerStamp) {
return new PointerType();
} else {
return stamp.javaType(metaAccess);
}
}
@Override
public void generate(NodeLIRBuilderTool generator) {
AArch64NodeLIRBuilder gen = (AArch64NodeLIRBuilder) generator;
Value[] parameter = new Value[args.count()];
JavaType[] parameterTypes = new JavaType[args.count()];
for (int i = 0; i < args.count(); i++) {
parameter[i] = generator.operand(args.get(i));
parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
}
JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
generator.getLIRGeneratorTool());
gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter);
if (this.getStackKind() != JavaKind.Void) {
generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
}
}
}

@ -1,130 +0,0 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.amd64;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
import org.graalvm.compiler.core.common.type.RawPointerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.NodeSize;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Value;
@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = NodeSize.SIZE_UNKNOWN)
public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
protected final JavaConstant functionPointer;
@Input NodeInputList<ValueNode> args;
public AMD64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
super(TYPE, StampFactory.forKind(returnType));
this.functionPointer = functionPointer;
this.args = new NodeInputList<>(this, args);
}
private static class PointerType implements JavaType {
@Override
public String getName() {
return "void*";
}
@Override
public JavaType getComponentType() {
return null;
}
@Override
public JavaType getArrayClass() {
return null;
}
@Override
public JavaKind getJavaKind() {
// native pointers and java objects use the same registers in the calling convention
return JavaKind.Object;
}
@Override
public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
return null;
}
}
private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
if (stamp instanceof RawPointerStamp) {
return new PointerType();
} else {
return stamp.javaType(metaAccess);
}
}
@Override
public void generate(NodeLIRBuilderTool generator) {
AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
Value[] parameter = new Value[args.count()];
JavaType[] parameterTypes = new JavaType[args.count()];
for (int i = 0; i < args.count(); i++) {
parameter[i] = generator.operand(args.get(i));
parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
}
JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
generator.getLIRGeneratorTool());
gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
if (this.getStackKind() != JavaKind.Void) {
generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
}
}
private static int countFloatingTypeArguments(NodeInputList<ValueNode> args) {
int count = 0;
for (ValueNode n : args) {
if (n.getStackKind() == JavaKind.Double || n.getStackKind() == JavaKind.Float) {
count++;
}
}
if (count > 8) {
return 8;
}
return count;
}
}

@ -207,7 +207,6 @@ public class CheckGraalIntrinsics extends GraalTest {
"oracle/jrockit/jfr/Timing.counterTime()J", "oracle/jrockit/jfr/Timing.counterTime()J",
"oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J", "oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J",
"oracle/jrockit/jfr/VMJFR.threadID()I", "oracle/jrockit/jfr/VMJFR.threadID()I",
"sun/misc/Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
"sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I", "sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I",
"sun/security/provider/DigestBase.implCompressMultiBlock([BII)I", "sun/security/provider/DigestBase.implCompressMultiBlock([BII)I",
"sun/security/provider/SHA.implCompress([BI)V", "sun/security/provider/SHA.implCompress([BI)V",
@ -273,7 +272,6 @@ public class CheckGraalIntrinsics extends GraalTest {
"jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S", "jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S",
"jdk/internal/misc/Unsafe.compareAndSetByte(Ljava/lang/Object;JBB)Z", "jdk/internal/misc/Unsafe.compareAndSetByte(Ljava/lang/Object;JBB)Z",
"jdk/internal/misc/Unsafe.compareAndSetShort(Ljava/lang/Object;JSS)Z", "jdk/internal/misc/Unsafe.compareAndSetShort(Ljava/lang/Object;JSS)Z",
"jdk/internal/misc/Unsafe.copyMemory0(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
"jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B", "jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B",
"jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S", "jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S",
"jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B", "jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B",

@ -0,0 +1,81 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.test;
import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
import org.junit.Test;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import sun.misc.Unsafe;
/**
* Tests the VM independent intrinsification of {@link Unsafe} methods.
*/
public class HotSpotUnsafeSubstitutionTest extends MethodSubstitutionTest {
public void testSubstitution(String testMethodName, Class<?> holder, String methodName, Class<?>[] parameterTypes, Object receiver, Object[] args1, Object[] args2) {
ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
ResolvedJavaMethod originalMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
// Force compilation
InstalledCode code = getCode(testMethod);
assert code != null;
// Verify that the original method and the substitution produce the same value
Object expected = invokeSafe(originalMethod, receiver, args1);
Object actual = invokeSafe(testMethod, null, args2);
assertDeepEquals(expected, actual);
// Verify that the generated code and the original produce the same value
expected = invokeSafe(originalMethod, receiver, args1);
actual = executeVarargsSafe(code, args2);
assertDeepEquals(expected, actual);
}
@Test
public void testUnsafeSubstitutions() throws Exception {
testGraph("unsafeCopyMemory");
}
public void unsafeCopyMemory(Object srcBase, long srcOffset, Object dstBase, long dstOffset, long bytes) {
UNSAFE.copyMemory(srcBase, srcOffset, dstBase, dstOffset, bytes);
}
public byte[] testCopyMemorySnippet(long src, int bytes) {
byte[] result = new byte[bytes];
UNSAFE.copyMemory(null, src, result, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes);
return result;
}
@Test
public void testCopyMemory() {
int size = 128;
long src = UNSAFE.allocateMemory(size);
for (int i = 0; i < size; i++) {
UNSAFE.putByte(null, src + i, (byte) i);
}
test("testCopyMemorySnippet", src, size);
}
}

@ -64,9 +64,9 @@ import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.tiers.SuitesProvider; import org.graalvm.compiler.phases.tiers.SuitesProvider;
import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.Word;
import org.graalvm.util.Equivalence;
import org.graalvm.util.EconomicMap; import org.graalvm.util.EconomicMap;
import org.graalvm.util.EconomicSet; import org.graalvm.util.EconomicSet;
import org.graalvm.util.Equivalence;
import org.graalvm.util.MapCursor; import org.graalvm.util.MapCursor;
import org.graalvm.word.Pointer; import org.graalvm.word.Pointer;
@ -257,6 +257,18 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen
@NodeIntrinsic(ForeignCallNode.class) @NodeIntrinsic(ForeignCallNode.class)
private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
/**
* @see org.graalvm.compiler.hotspot.meta.HotSpotUnsafeSubstitutions#copyMemory
*/
public static final ForeignCallDescriptor UNSAFE_ARRAYCOPY = new ForeignCallDescriptor("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class);
public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) {
unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size);
}
@NodeIntrinsic(ForeignCallNode.class)
private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size);
/** /**
* @see VMErrorNode * @see VMErrorNode
*/ */

@ -198,7 +198,7 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) { public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug); StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug);
CompilationResult result = new CompilationResult(); CompilationResult result = new CompilationResult(compilationId);
return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options); return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options);
} }

@ -111,6 +111,7 @@ import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
import sun.misc.Unsafe;
/** /**
* Defines the {@link Plugins} used when running on HotSpot. * Defines the {@link Plugins} used when running on HotSpot.
@ -202,6 +203,7 @@ public class HotSpotGraphBuilderPlugins {
registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider); registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider); registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider); registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider);
StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true); StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) { for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
@ -313,6 +315,17 @@ public class HotSpotGraphBuilderPlugins {
r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class); r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
} }
private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementBytecodeProvider) {
Registration r;
if (Java8OrEarlier) {
r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
} else {
r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
}
r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, "copyMemory", Receiver.class, Object.class, long.class, Object.class, long.class,
long.class);
}
private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants"); private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length"); private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");

@ -51,6 +51,7 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS; import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS; import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN; import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN;
import static org.graalvm.compiler.hotspot.HotSpotBackend.UNSAFE_ARRAYCOPY;
import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR; import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR;
import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER; import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER;
@ -330,6 +331,8 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall
registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit); registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy); registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
registerForeignCall(UNSAFE_ARRAYCOPY, c.unsafeArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
if (c.useMultiplyToLenIntrinsic()) { if (c.useMultiplyToLenIntrinsic()) {
registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int)); registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
} }

@ -0,0 +1,47 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.meta;
import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
import org.graalvm.compiler.api.replacements.ClassSubstitution;
import org.graalvm.compiler.api.replacements.MethodSubstitution;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
import org.graalvm.compiler.word.Word;
import org.graalvm.word.WordFactory;
@ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"})
public class HotSpotUnsafeSubstitutions {
public static final String copyMemoryName = Java8OrEarlier ? "copyMemory" : "copyMemory0";
@SuppressWarnings("unused")
@MethodSubstitution(isStatic = false)
static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
Word size = Word.signed(bytes);
HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
}
}

@ -216,8 +216,9 @@ public abstract class Stub {
@SuppressWarnings("try") @SuppressWarnings("try")
private CompilationResult buildCompilationResult(DebugContext debug, final Backend backend) { private CompilationResult buildCompilationResult(DebugContext debug, final Backend backend) {
CompilationResult compResult = new CompilationResult(toString(), GeneratePIC.getValue(options)); CompilationIdentifier compilationId = getStubCompilationId();
final StructuredGraph graph = getGraph(debug, getStubCompilationId()); final StructuredGraph graph = getGraph(debug, compilationId);
CompilationResult compResult = new CompilationResult(compilationId, toString(), GeneratePIC.getValue(options));
// Stubs cannot be recompiled so they cannot be compiled with assumptions // Stubs cannot be recompiled so they cannot be compiled with assumptions
assert graph.getAssumptions() == null; assert graph.getAssumptions() == null;

@ -365,10 +365,6 @@ final class TraceInterval extends IntervalHint {
return intTo; return intTo;
} }
int numUsePositions() {
return numUsePos();
}
public void setLocationHint(IntervalHint interval) { public void setLocationHint(IntervalHint interval) {
locationHint = interval; locationHint = interval;
} }
@ -452,6 +448,10 @@ final class TraceInterval extends IntervalHint {
return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize()); return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
} }
public boolean preSpilledAllocated() {
return spillState() == SpillState.StartInMemory && numUsePos() == 0 && !hasHint();
}
// test intersection // test intersection
boolean intersects(TraceInterval i) { boolean intersects(TraceInterval i) {
return intersectsAt(i) != -1; return intersectsAt(i) != -1;

@ -541,16 +541,23 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
assert instructionIndex == 0 : "not at start?" + instructionIndex; assert instructionIndex == 0 : "not at start?" + instructionIndex;
handleTraceBegin(blocks[0]); handleTraceBegin(blocks[0]);
// fix spill state for phi/incoming intervals
for (TraceInterval interval : allocator.intervals()) {
if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
// there was a definition in a phi/incoming
interval.setSpillState(SpillState.NoSpillStore);
}
}
if (TraceRAuseInterTraceHints.getValue(allocator.getLIR().getOptions())) { if (TraceRAuseInterTraceHints.getValue(allocator.getLIR().getOptions())) {
addInterTraceHints(); addInterTraceHints();
} }
// fix spill state for phi/incoming intervals
for (TraceInterval interval : allocator.intervals()) {
if (interval != null) {
if (interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
// there was a definition in a phi/incoming
interval.setSpillState(SpillState.NoSpillStore);
}
if (interval.preSpilledAllocated()) {
// pre-spill unused, start in memory intervals
allocator.assignSpillSlot(interval);
}
}
}
for (FixedInterval interval1 : allocator.fixedIntervals()) { for (FixedInterval interval1 : allocator.fixedIntervals()) {
if (interval1 != null) { if (interval1 != null) {
/* We use [-1, 0] to avoid intersection with incoming values. */ /* We use [-1, 0] to avoid intersection with incoming values. */

@ -153,7 +153,7 @@ public final class TraceLinearScanPhase extends TraceAllocationPhase<TraceAlloca
@Override @Override
public boolean apply(TraceInterval i) { public boolean apply(TraceInterval i) {
// all TraceIntervals are variable intervals // all TraceIntervals are variable intervals
return true; return !i.preSpilledAllocated();
} }
}; };
private static final Comparator<TraceInterval> SORT_BY_FROM_COMP = new Comparator<TraceInterval>() { private static final Comparator<TraceInterval> SORT_BY_FROM_COMP = new Comparator<TraceInterval>() {

@ -319,7 +319,7 @@ public abstract class GraalCompilerState {
assert !graph.isFrozen(); assert !graph.isFrozen();
ResolvedJavaMethod installedCodeOwner = graph.method(); ResolvedJavaMethod installedCodeOwner = graph.method();
request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default); graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
} }
/** /**

@ -209,7 +209,6 @@ public class GraphEncoder {
int nodeCount = nodeOrder.nextOrderId; int nodeCount = nodeOrder.nextOrderId;
assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID; assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID;
assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID; assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID;
assert nodeCount == graph.getNodeCount() + 1;
long[] nodeStartOffsets = new long[nodeCount]; long[] nodeStartOffsets = new long[nodeCount];
UnmodifiableMapCursor<Node, Integer> cursor = nodeOrder.orderIds.getEntries(); UnmodifiableMapCursor<Node, Integer> cursor = nodeOrder.orderIds.getEntries();
@ -218,6 +217,7 @@ public class GraphEncoder {
Integer orderId = cursor.getValue(); Integer orderId = cursor.getValue();
assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET; assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET;
assert nodeStartOffsets[orderId] == 0;
nodeStartOffsets[orderId] = writer.getBytesWritten(); nodeStartOffsets[orderId] = writer.getBytesWritten();
/* Write out the type, properties, and edges. */ /* Write out the type, properties, and edges. */
@ -284,7 +284,6 @@ public class GraphEncoder {
writer.putUV(nodeOrder.maxFixedNodeOrderId); writer.putUV(nodeOrder.maxFixedNodeOrderId);
writer.putUV(nodeCount); writer.putUV(nodeCount);
for (int i = 0; i < nodeCount; i++) { for (int i = 0; i < nodeCount; i++) {
assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0;
writer.putUV(metadataStart - nodeStartOffsets[i]); writer.putUV(metadataStart - nodeStartOffsets[i]);
} }
@ -344,8 +343,25 @@ public class GraphEncoder {
} while (current != null); } while (current != null);
maxFixedNodeOrderId = nextOrderId - 1; maxFixedNodeOrderId = nextOrderId - 1;
/*
* Emit all parameters consecutively at a known location (after all fixed nodes). This
* allows substituting parameters when inlining during decoding by pre-initializing the
* decoded node list.
*
* Note that not all parameters must be present (unused parameters are deleted after
* parsing). This leads to holes in the orderId, i.e., unused orderIds.
*/
int parameterCount = graph.method().getSignature().getParameterCount(!graph.method().isStatic());
for (ParameterNode node : graph.getNodes(ParameterNode.TYPE)) {
assert orderIds.get(node) == null : "Parameter node must not be ordered yet";
assert node.index() < parameterCount : "Parameter index out of range";
orderIds.set(node, nextOrderId + node.index());
}
nextOrderId += parameterCount;
for (Node node : graph.getNodes()) { for (Node node : graph.getNodes()) {
assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered: " + node; assert (node instanceof FixedNode || node instanceof ParameterNode) == (orderIds.get(node) != null) : "all fixed nodes and ParameterNodes must be ordered: " + node;
add(node); add(node);
} }
} }

@ -37,6 +37,7 @@ import java.util.List;
import org.graalvm.compiler.bytecode.BytecodeDisassembler; import org.graalvm.compiler.bytecode.BytecodeDisassembler;
import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.code.DisassemblerProvider; import org.graalvm.compiler.code.DisassemblerProvider;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.alloc.Trace; import org.graalvm.compiler.core.common.alloc.Trace;
import org.graalvm.compiler.core.common.alloc.TraceBuilderResult; import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@ -72,6 +73,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
private CFGPrinter cfgPrinter; private CFGPrinter cfgPrinter;
private File cfgFile; private File cfgFile;
private JavaMethod curMethod; private JavaMethod curMethod;
private CompilationIdentifier curCompilation;
private List<String> curDecorators = Collections.emptyList(); private List<String> curDecorators = Collections.emptyList();
@Override @Override
@ -92,6 +94,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
*/ */
private boolean checkMethodScope(DebugContext debug) { private boolean checkMethodScope(DebugContext debug) {
JavaMethod method = null; JavaMethod method = null;
CompilationIdentifier compilation = null;
ArrayList<String> decorators = new ArrayList<>(); ArrayList<String> decorators = new ArrayList<>();
for (Object o : debug.context()) { for (Object o : debug.context()) {
if (o instanceof JavaMethod) { if (o instanceof JavaMethod) {
@ -102,22 +105,33 @@ public class CFGPrinterObserver implements DebugDumpHandler {
if (graph.method() != null) { if (graph.method() != null) {
method = graph.method(); method = graph.method();
decorators.clear(); decorators.clear();
compilation = graph.compilationId();
} }
} else if (o instanceof DebugDumpScope) { } else if (o instanceof DebugDumpScope) {
DebugDumpScope debugDumpScope = (DebugDumpScope) o; DebugDumpScope debugDumpScope = (DebugDumpScope) o;
if (debugDumpScope.decorator) { if (debugDumpScope.decorator) {
decorators.add(debugDumpScope.name); decorators.add(debugDumpScope.name);
} }
} else if (o instanceof CompilationResult) {
CompilationResult compilationResult = (CompilationResult) o;
compilation = compilationResult.getCompilationId();
} }
} }
if (method == null) { if (method == null && compilation == null) {
return false; return false;
} }
if (!method.equals(curMethod) || !curDecorators.equals(decorators)) { if (compilation != null) {
cfgPrinter.printCompilation(method); if (!compilation.equals(curCompilation) || !curDecorators.equals(decorators)) {
cfgPrinter.printCompilation(compilation);
}
} else {
if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
cfgPrinter.printCompilation(method);
}
} }
curCompilation = compilation;
curMethod = method; curMethod = method;
curDecorators = decorators; curDecorators = decorators;
return true; return true;
@ -277,6 +291,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
cfgPrinter = null; cfgPrinter = null;
curDecorators = Collections.emptyList(); curDecorators = Collections.emptyList();
curMethod = null; curMethod = null;
curCompilation = null;
} }
} }

@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.debug.LogStream; import org.graalvm.compiler.debug.LogStream;
import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.lir.util.IndexedValueMap; import org.graalvm.compiler.lir.util.IndexedValueMap;
@ -115,12 +116,25 @@ public class CompilationPrinter implements Closeable {
/** /**
* Prints a compilation timestamp for a given method. * Prints a compilation timestamp for a given method.
* *
* @param method the method for which a timestamp will be printed * @param javaMethod the method for which a timestamp will be printed
*/ */
public void printCompilation(JavaMethod method) { public void printCompilation(JavaMethod javaMethod) {
printCompilation(javaMethod.format("%H::%n"), javaMethod.format("%f %r %H.%n(%p)"));
}
/**
* Prints a compilation id.
*
* @param compilationId the compilation method for which an id will be printed
*/
public void printCompilation(CompilationIdentifier compilationId) {
printCompilation(compilationId.toString(CompilationIdentifier.Verbosity.DETAILED), compilationId.toString(CompilationIdentifier.Verbosity.DETAILED));
}
private void printCompilation(final String name, String method) {
begin("compilation"); begin("compilation");
out.print("name \" ").print(method.format("%H::%n")).println('"'); out.print("name \" ").print(name).println('"');
out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"'); out.print("method \"").print(method).println('"');
out.print("date ").println(System.currentTimeMillis()); out.print("date ").println(System.currentTimeMillis());
end("compilation"); end("compilation");
} }

@ -95,10 +95,13 @@ public final class ClassSubstitutionVerifier extends AbstractVerifier {
TypeElement typeElement = null; TypeElement typeElement = null;
for (String className : classNames) { for (String className : classNames) {
typeElement = env.getElementUtils().getTypeElement(className); typeElement = env.getElementUtils().getTypeElement(className);
if (typeElement == null && !optional) { if (typeElement != null) {
env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue); break;
} }
} }
if (typeElement == null && !optional) {
env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
}
return typeElement; return typeElement;
} }

@ -707,10 +707,22 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
} }
} }
LoopScope inlineLoopScope = createInitialLoopScope(inlineScope, predecessor);
/*
* The GraphEncoder assigns parameters a nodeId immediately after the fixed nodes.
* Initializing createdNodes here avoid decoding and immediately replacing the
* ParameterNodes.
*/
int firstArgumentNodeId = inlineScope.maxFixedNodeOrderId + 1;
for (int i = 0; i < arguments.length; i++) {
inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i];
}
/* /*
* Do the actual inlining by returning the initial loop scope for the inlined method scope. * Do the actual inlining by returning the initial loop scope for the inlined method scope.
*/ */
return createInitialLoopScope(inlineScope, predecessor); return inlineLoopScope;
} }
@Override @Override
@ -1028,9 +1040,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
if (node instanceof ParameterNode) { if (node instanceof ParameterNode) {
ParameterNode param = (ParameterNode) node; ParameterNode param = (ParameterNode) node;
if (methodScope.isInlinedMethod()) { if (methodScope.isInlinedMethod()) {
Node result = methodScope.arguments[param.index()]; throw GraalError.shouldNotReachHere("Parameter nodes are already registered when the inlined scope is created");
assert result != null;
return result;
} else if (parameterPlugin != null) { } else if (parameterPlugin != null) {
assert !methodScope.isInlinedMethod(); assert !methodScope.isInlinedMethod();

@ -1185,62 +1185,6 @@ const char* os::dll_file_extension() { return ".so"; }
// directory not the java application's temp directory, ala java.io.tmpdir. // directory not the java application's temp directory, ala java.io.tmpdir.
const char* os::get_temp_directory() { return "/tmp"; } const char* os::get_temp_directory() { return "/tmp"; }
static bool file_exists(const char* filename) {
struct stat statbuf;
if (filename == NULL || strlen(filename) == 0) {
return false;
}
return os::stat(filename, &statbuf) == 0;
}
bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
*buffer = '\0';
return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
if (pelements == NULL) {
return false;
}
for (int i = 0; i < n; i++) {
// Really shouldn't be NULL, but check can't hurt
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
continue; // skip the empty path values
}
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
if (file_exists(buffer)) {
retval = true;
break;
}
}
// release the storage
for (int i = 0; i < n; i++) {
if (pelements[i] != NULL) {
FREE_C_HEAP_ARRAY(char, pelements[i]);
}
}
if (pelements != NULL) {
FREE_C_HEAP_ARRAY(char*, pelements);
}
} else {
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
retval = true;
}
return retval;
}
// Check if addr is inside libjvm.so. // Check if addr is inside libjvm.so.
bool os::address_is_in_vm(address addr) { bool os::address_is_in_vm(address addr) {
@ -1493,12 +1437,7 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) {
} }
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
st->print("CPU:"); // Nothing to do beyond what os::print_cpu_info() does.
st->print("total %d", os::processor_count());
// It's not safe to query number of active processors after crash.
// st->print("(active %d)", os::active_processor_count());
st->print(" %s", VM_Version::features());
st->cr();
} }
static void print_signal_handler(outputStream* st, int sig, static void print_signal_handler(outputStream* st, int sig,
@ -2668,11 +2607,10 @@ void os::hint_no_preempt() {}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// suspend/resume support // suspend/resume support
// the low-level signal-based suspend/resume support is a remnant from the // The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc, // old VM-suspension that used to be for java-suspension, safepoints etc,
// within hotspot. Now there is a single use-case for this: // within hotspot. Currently used by JFR's OSThreadSampler
// - calling get_thread_pc() on the VMThread by the flat-profiler task //
// that runs in the watcher thread.
// The remaining code is greatly simplified from the more general suspension // The remaining code is greatly simplified from the more general suspension
// code that used to be used. // code that used to be used.
// //
@ -2688,7 +2626,13 @@ void os::hint_no_preempt() {}
// //
// Note that the SR_lock plays no role in this suspend/resume protocol, // Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator. // but is checked for NULL in SR_handler as a thread termination indicator.
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
// //
// Note that resume_clear_context() and suspend_save_context() are needed
// by SR_handler(), so that fetch_frame_from_ucontext() works,
// which in part is used by:
// - Forte Analyzer: AsyncGetCallTrace()
// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) { static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL); osthread->set_ucontext(NULL);
@ -3695,44 +3639,6 @@ void os::SuspendedThreadTask::internal_do_task() {
} }
} }
class PcFetcher : public os::SuspendedThreadTask {
public:
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
ExtendedPC result();
protected:
void do_task(const os::SuspendedThreadTaskContext& context);
private:
ExtendedPC _epc;
};
ExtendedPC PcFetcher::result() {
guarantee(is_done(), "task is not done yet.");
return _epc;
}
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
Thread* thread = context.thread();
OSThread* osthread = thread->osthread();
if (osthread->ucontext() != NULL) {
_epc = os::Aix::ucontext_get_pc((const ucontext_t *) context.ucontext());
} else {
// NULL context is unexpected, double-check this is the VMThread.
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
}
}
// Suspends the target using the signal mechanism and then grabs the PC before
// resuming the target. Used by the flat-profiler only
ExtendedPC os::get_thread_pc(Thread* thread) {
// Make sure that it is called by the watcher for the VMThread.
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
assert(thread->is_VM_thread(), "Can only be called for VMThread");
PcFetcher fetcher(thread);
fetcher.run();
return fetcher.result();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// debug support // debug support

@ -1172,13 +1172,6 @@ int os::current_process_id() {
// DLL functions // DLL functions
#define JNI_LIB_PREFIX "lib"
#ifdef __APPLE__
#define JNI_LIB_SUFFIX ".dylib"
#else
#define JNI_LIB_SUFFIX ".so"
#endif
const char* os::dll_file_extension() { return JNI_LIB_SUFFIX; } const char* os::dll_file_extension() { return JNI_LIB_SUFFIX; }
// This must be hard coded because it's the system's temporary // This must be hard coded because it's the system's temporary
@ -1201,62 +1194,6 @@ const char* os::get_temp_directory() {
const char* os::get_temp_directory() { return "/tmp"; } const char* os::get_temp_directory() { return "/tmp"; }
#endif // __APPLE__ #endif // __APPLE__
static bool file_exists(const char* filename) {
struct stat statbuf;
if (filename == NULL || strlen(filename) == 0) {
return false;
}
return os::stat(filename, &statbuf) == 0;
}
bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + strlen(JNI_LIB_PREFIX) + strlen(JNI_LIB_SUFFIX) + 2 > buflen) {
return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, fname);
retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
if (pelements == NULL) {
return false;
}
for (int i = 0; i < n; i++) {
// Really shouldn't be NULL, but check can't hurt
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
continue; // skip the empty path values
}
snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX,
pelements[i], fname);
if (file_exists(buffer)) {
retval = true;
break;
}
}
// release the storage
for (int i = 0; i < n; i++) {
if (pelements[i] != NULL) {
FREE_C_HEAP_ARRAY(char, pelements[i]);
}
}
if (pelements != NULL) {
FREE_C_HEAP_ARRAY(char*, pelements);
}
} else {
snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, pname, fname);
retval = true;
}
return retval;
}
// check if addr is inside libjvm.so // check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) { bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr; static address libjvm_base_addr;
@ -2666,11 +2603,10 @@ void os::hint_no_preempt() {}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// suspend/resume support // suspend/resume support
// the low-level signal-based suspend/resume support is a remnant from the // The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc, // old VM-suspension that used to be for java-suspension, safepoints etc,
// within hotspot. Now there is a single use-case for this: // within hotspot. Currently used by JFR's OSThreadSampler
// - calling get_thread_pc() on the VMThread by the flat-profiler task //
// that runs in the watcher thread.
// The remaining code is greatly simplified from the more general suspension // The remaining code is greatly simplified from the more general suspension
// code that used to be used. // code that used to be used.
// //
@ -2686,6 +2622,13 @@ void os::hint_no_preempt() {}
// //
// Note that the SR_lock plays no role in this suspend/resume protocol, // Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator. // but is checked for NULL in SR_handler as a thread termination indicator.
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
//
// Note that resume_clear_context() and suspend_save_context() are needed
// by SR_handler(), so that fetch_frame_from_ucontext() works,
// which in part is used by:
// - Forte Analyzer: AsyncGetCallTrace()
// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) { static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL); osthread->set_ucontext(NULL);
@ -3584,45 +3527,6 @@ void os::SuspendedThreadTask::internal_do_task() {
} }
} }
///
class PcFetcher : public os::SuspendedThreadTask {
public:
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
ExtendedPC result();
protected:
void do_task(const os::SuspendedThreadTaskContext& context);
private:
ExtendedPC _epc;
};
ExtendedPC PcFetcher::result() {
guarantee(is_done(), "task is not done yet.");
return _epc;
}
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
Thread* thread = context.thread();
OSThread* osthread = thread->osthread();
if (osthread->ucontext() != NULL) {
_epc = os::Bsd::ucontext_get_pc((const ucontext_t *) context.ucontext());
} else {
// NULL context is unexpected, double-check this is the VMThread
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
}
}
// Suspends the target using the signal mechanism and then grabs the PC before
// resuming the target. Used by the flat-profiler only
ExtendedPC os::get_thread_pc(Thread* thread) {
// Make sure that it is called by the watcher for the VMThread
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
assert(thread->is_VM_thread(), "Can only be called for VMThread");
PcFetcher fetcher(thread);
fetcher.run();
return fetcher.result();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// debug support // debug support

@ -1419,53 +1419,6 @@ static bool file_exists(const char* filename) {
return os::stat(filename, &statbuf) == 0; return os::stat(filename, &statbuf) == 0;
} }
bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
if (pelements == NULL) {
return false;
}
for (int i = 0; i < n; i++) {
// Really shouldn't be NULL, but check can't hurt
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
continue; // skip the empty path values
}
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
if (file_exists(buffer)) {
retval = true;
break;
}
}
// release the storage
for (int i = 0; i < n; i++) {
if (pelements[i] != NULL) {
FREE_C_HEAP_ARRAY(char, pelements[i]);
}
}
if (pelements != NULL) {
FREE_C_HEAP_ARRAY(char*, pelements);
}
} else {
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
retval = true;
}
return retval;
}
// check if addr is inside libjvm.so // check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) { bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr; static address libjvm_base_addr;
@ -4047,11 +4000,10 @@ void os::hint_no_preempt() {}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// suspend/resume support // suspend/resume support
// the low-level signal-based suspend/resume support is a remnant from the // The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc, // old VM-suspension that used to be for java-suspension, safepoints etc,
// within hotspot. Now there is a single use-case for this: // within hotspot. Currently used by JFR's OSThreadSampler
// - calling get_thread_pc() on the VMThread by the flat-profiler task //
// that runs in the watcher thread.
// The remaining code is greatly simplified from the more general suspension // The remaining code is greatly simplified from the more general suspension
// code that used to be used. // code that used to be used.
// //
@ -4067,6 +4019,13 @@ void os::hint_no_preempt() {}
// //
// Note that the SR_lock plays no role in this suspend/resume protocol, // Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator. // but is checked for NULL in SR_handler as a thread termination indicator.
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
//
// Note that resume_clear_context() and suspend_save_context() are needed
// by SR_handler(), so that fetch_frame_from_ucontext() works,
// which in part is used by:
// - Forte Analyzer: AsyncGetCallTrace()
// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) { static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL); osthread->set_ucontext(NULL);
@ -5107,44 +5066,6 @@ void os::SuspendedThreadTask::internal_do_task() {
} }
} }
class PcFetcher : public os::SuspendedThreadTask {
public:
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
ExtendedPC result();
protected:
void do_task(const os::SuspendedThreadTaskContext& context);
private:
ExtendedPC _epc;
};
ExtendedPC PcFetcher::result() {
guarantee(is_done(), "task is not done yet.");
return _epc;
}
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
Thread* thread = context.thread();
OSThread* osthread = thread->osthread();
if (osthread->ucontext() != NULL) {
_epc = os::Linux::ucontext_get_pc((const ucontext_t *) context.ucontext());
} else {
// NULL context is unexpected, double-check this is the VMThread
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
}
}
// Suspends the target using the signal mechanism and then grabs the PC before
// resuming the target. Used by the flat-profiler only
ExtendedPC os::get_thread_pc(Thread* thread) {
// Make sure that it is called by the watcher for the VMThread
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
assert(thread->is_VM_thread(), "Can only be called for VMThread");
PcFetcher fetcher(thread);
fetcher.run();
return fetcher.result();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// debug support // debug support

@ -24,7 +24,6 @@
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
#include "prims/jvm.h" #include "prims/jvm.h"
#include "semaphore_posix.hpp"
#include "runtime/frame.inline.hpp" #include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.hpp" #include "runtime/interfaceSupport.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
@ -32,6 +31,11 @@
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#ifndef __APPLE__
// POSIX unamed semaphores are not supported on OS X.
#include "semaphore_posix.hpp"
#endif
#include <dlfcn.h> #include <dlfcn.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -65,12 +65,6 @@
void set_lwp_id(uint id) { _lwp_id = id; } void set_lwp_id(uint id) { _lwp_id = id; }
void set_native_priority(int prio) { _native_priority = prio; } void set_native_priority(int prio) { _native_priority = prio; }
// ***************************************************************
// interrupt support. interrupts (using signals) are used to get
// the thread context (get_thread_pc), to set the thread context
// (set_thread_pc), and to implement java.lang.Thread.interrupt.
// ***************************************************************
public: public:
os::SuspendResume sr; os::SuspendResume sr;

@ -1356,60 +1356,6 @@ const char* os::dll_file_extension() { return ".so"; }
// directory not the java application's temp directory, ala java.io.tmpdir. // directory not the java application's temp directory, ala java.io.tmpdir.
const char* os::get_temp_directory() { return "/tmp"; } const char* os::get_temp_directory() { return "/tmp"; }
static bool file_exists(const char* filename) {
struct stat statbuf;
if (filename == NULL || strlen(filename) == 0) {
return false;
}
return os::stat(filename, &statbuf) == 0;
}
bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
const size_t pnamelen = pname ? strlen(pname) : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
if (pelements == NULL) {
return false;
}
for (int i = 0; i < n; i++) {
// really shouldn't be NULL but what the heck, check can't hurt
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
continue; // skip the empty path values
}
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
if (file_exists(buffer)) {
retval = true;
break;
}
}
// release the storage
for (int i = 0; i < n; i++) {
if (pelements[i] != NULL) {
FREE_C_HEAP_ARRAY(char, pelements[i]);
}
}
if (pelements != NULL) {
FREE_C_HEAP_ARRAY(char*, pelements);
}
} else {
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
retval = true;
}
return retval;
}
// check if addr is inside libjvm.so // check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) { bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr; static address libjvm_base_addr;
@ -3496,6 +3442,37 @@ void os::hint_no_preempt() {
schedctl_start(schedctl_init()); schedctl_start(schedctl_init());
} }
////////////////////////////////////////////////////////////////////////////////
// suspend/resume support
// The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc,
// within hotspot. Currently used by JFR's OSThreadSampler
//
// The remaining code is greatly simplified from the more general suspension
// code that used to be used.
//
// The protocol is quite simple:
// - suspend:
// - sends a signal to the target thread
// - polls the suspend state of the osthread using a yield loop
// - target thread signal handler (SR_handler) sets suspend state
// and blocks in sigsuspend until continued
// - resume:
// - sets target osthread state to continue
// - sends signal to end the sigsuspend loop in the SR_handler
//
// Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator.
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
//
// Note that resume_clear_context() and suspend_save_context() are needed
// by SR_handler(), so that fetch_frame_from_ucontext() works,
// which in part is used by:
// - Forte Analyzer: AsyncGetCallTrace()
// - StackBanging: get_frame_at_stack_banging_point()
// - JFR: get_topframe()-->....-->get_valid_uc_in_signal_handler()
static void resume_clear_context(OSThread *osthread) { static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL); osthread->set_ucontext(NULL);
} }
@ -3506,7 +3483,7 @@ static void suspend_save_context(OSThread *osthread, ucontext_t* context) {
static PosixSemaphore sr_semaphore; static PosixSemaphore sr_semaphore;
void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) { void os::Solaris::SR_handler(Thread* thread, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR // Save and restore errno to avoid confusing native code with EINTR
// after sigsuspend. // after sigsuspend.
int old_errno = errno; int old_errno = errno;
@ -3516,7 +3493,7 @@ void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
os::SuspendResume::State current = osthread->sr.state(); os::SuspendResume::State current = osthread->sr.state();
if (current == os::SuspendResume::SR_SUSPEND_REQUEST) { if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
suspend_save_context(osthread, uc); suspend_save_context(osthread, context);
// attempt to switch the state, we assume we had a SUSPEND_REQUEST // attempt to switch the state, we assume we had a SUSPEND_REQUEST
os::SuspendResume::State state = osthread->sr.suspended(); os::SuspendResume::State state = osthread->sr.suspended();
@ -3663,45 +3640,6 @@ void os::SuspendedThreadTask::internal_do_task() {
} }
} }
class PcFetcher : public os::SuspendedThreadTask {
public:
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
ExtendedPC result();
protected:
void do_task(const os::SuspendedThreadTaskContext& context);
private:
ExtendedPC _epc;
};
ExtendedPC PcFetcher::result() {
guarantee(is_done(), "task is not done yet.");
return _epc;
}
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
Thread* thread = context.thread();
OSThread* osthread = thread->osthread();
if (osthread->ucontext() != NULL) {
_epc = os::Solaris::ucontext_get_pc((const ucontext_t *) context.ucontext());
} else {
// NULL context is unexpected, double-check this is the VMThread
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
}
}
// A lightweight implementation that does not suspend the target thread and
// thus returns only a hint. Used for profiling only!
ExtendedPC os::get_thread_pc(Thread* thread) {
// Make sure that it is called by the watcher and the Threads lock is owned.
assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock");
// For now, is only used to profile the VM Thread
assert(thread->is_VM_thread(), "Can only be called for VMThread");
PcFetcher fetcher(thread);
fetcher.run();
return fetcher.result();
}
// This does not do anything on Solaris. This is basically a hook for being // This does not do anything on Solaris. This is basically a hook for being
// able to use structured exception handling (thread-local exception filters) on, e.g., Win32. // able to use structured exception handling (thread-local exception filters) on, e.g., Win32.
void os::os_exception_wrapper(java_call_t f, JavaValue* value, void os::os_exception_wrapper(java_call_t f, JavaValue* value,

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,160 +27,99 @@
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "decoder_windows.hpp" #include "decoder_windows.hpp"
#include "windbghelp.hpp"
WindowsDecoder::WindowsDecoder() { WindowsDecoder::WindowsDecoder() {
_dbghelp_handle = NULL; _can_decode_in_vm = true;
_can_decode_in_vm = false;
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
#ifdef AMD64
_pfnStackWalk64 = NULL;
_pfnSymFunctionTableAccess64 = NULL;
_pfnSymGetModuleBase64 = NULL;
#endif
_decoder_status = no_error; _decoder_status = no_error;
initialize(); initialize();
} }
void WindowsDecoder::initialize() { void WindowsDecoder::initialize() {
if (!has_error() && _dbghelp_handle == NULL) { if (!has_error()) {
HMODULE handle = ::LoadLibrary("dbghelp.dll");
if (!handle) {
_decoder_status = helper_not_found;
return;
}
_dbghelp_handle = handle;
pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions");
pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize");
_pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64");
_pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName");
if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
uninitialize();
_decoder_status = helper_func_error;
return;
}
#ifdef AMD64
_pfnStackWalk64 = (pfn_StackWalk64)::GetProcAddress(handle, "StackWalk64");
_pfnSymFunctionTableAccess64 = (pfn_SymFunctionTableAccess64)::GetProcAddress(handle, "SymFunctionTableAccess64");
_pfnSymGetModuleBase64 = (pfn_SymGetModuleBase64)::GetProcAddress(handle, "SymGetModuleBase64");
if (_pfnStackWalk64 == NULL || _pfnSymFunctionTableAccess64 == NULL || _pfnSymGetModuleBase64 == NULL) {
// We can't call StackWalk64 to walk the stack, but we are still
// able to decode the symbols. Let's limp on.
_pfnStackWalk64 = NULL;
_pfnSymFunctionTableAccess64 = NULL;
_pfnSymGetModuleBase64 = NULL;
}
#endif
HANDLE hProcess = ::GetCurrentProcess(); HANDLE hProcess = ::GetCurrentProcess();
_pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS); WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
if (!_pfnSymInitialize(hProcess, NULL, TRUE)) { if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
::FreeLibrary(handle);
_dbghelp_handle = NULL;
_decoder_status = helper_init_error; _decoder_status = helper_init_error;
return; return;
} }
// set pdb search paths // set pdb search paths
pfn_SymSetSearchPath _pfn_SymSetSearchPath = char paths[MAX_PATH];
(pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath"); int len = sizeof(paths);
pfn_SymGetSearchPath _pfn_SymGetSearchPath = if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) {
(pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath"); paths[0] = '\0';
if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) { } else {
char paths[MAX_PATH]; // available spaces in path buffer
int len = sizeof(paths); len -= (int)strlen(paths);
if (!_pfn_SymGetSearchPath(hProcess, paths, len)) {
paths[0] = '\0';
} else {
// available spaces in path buffer
len -= (int)strlen(paths);
}
char tmp_path[MAX_PATH];
DWORD dwSize;
HMODULE hJVM = ::GetModuleHandle("jvm.dll");
tmp_path[0] = '\0';
// append the path where jvm.dll is located
if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
while (dwSize > 0 && tmp_path[dwSize] != '\\') {
dwSize --;
}
tmp_path[dwSize] = '\0';
if (dwSize > 0 && len > (int)dwSize + 1) {
strncat(paths, os::path_separator(), 1);
strncat(paths, tmp_path, dwSize);
len -= dwSize + 1;
}
}
// append $JRE/bin. Arguments::get_java_home actually returns $JRE
// path
char *p = Arguments::get_java_home();
assert(p != NULL, "empty java home");
size_t java_home_len = strlen(p);
if (len > (int)java_home_len + 5) {
strncat(paths, os::path_separator(), 1);
strncat(paths, p, java_home_len);
strncat(paths, "\\bin", 4);
len -= (int)(java_home_len + 5);
}
// append $JDK/bin path if it exists
assert(java_home_len < MAX_PATH, "Invalid path length");
// assume $JRE is under $JDK, construct $JDK/bin path and
// see if it exists or not
if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
strncpy(tmp_path, p, java_home_len - 3);
tmp_path[java_home_len - 3] = '\0';
strncat(tmp_path, "bin", 3);
// if the directory exists
DWORD dwAttrib = GetFileAttributes(tmp_path);
if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
// tmp_path should have the same length as java_home_len, since we only
// replaced 'jre' with 'bin'
if (len > (int)java_home_len + 1) {
strncat(paths, os::path_separator(), 1);
strncat(paths, tmp_path, java_home_len);
}
}
}
_pfn_SymSetSearchPath(hProcess, paths);
} }
// find out if jvm.dll contains private symbols, by decoding char tmp_path[MAX_PATH];
// current function and comparing the result DWORD dwSize;
address addr = (address)Decoder::demangle; HMODULE hJVM = ::GetModuleHandle("jvm.dll");
char buf[MAX_PATH]; tmp_path[0] = '\0';
if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) { // append the path where jvm.dll is located
_can_decode_in_vm = !strcmp(buf, "Decoder::demangle"); if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
} while (dwSize > 0 && tmp_path[dwSize] != '\\') {
dwSize --;
}
tmp_path[dwSize] = '\0';
if (dwSize > 0 && len > (int)dwSize + 1) {
strncat(paths, os::path_separator(), 1);
strncat(paths, tmp_path, dwSize);
len -= dwSize + 1;
}
}
// append $JRE/bin. Arguments::get_java_home actually returns $JRE
// path
char *p = Arguments::get_java_home();
assert(p != NULL, "empty java home");
size_t java_home_len = strlen(p);
if (len > (int)java_home_len + 5) {
strncat(paths, os::path_separator(), 1);
strncat(paths, p, java_home_len);
strncat(paths, "\\bin", 4);
len -= (int)(java_home_len + 5);
}
// append $JDK/bin path if it exists
assert(java_home_len < MAX_PATH, "Invalid path length");
// assume $JRE is under $JDK, construct $JDK/bin path and
// see if it exists or not
if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
strncpy(tmp_path, p, java_home_len - 3);
tmp_path[java_home_len - 3] = '\0';
strncat(tmp_path, "bin", 3);
// if the directory exists
DWORD dwAttrib = GetFileAttributes(tmp_path);
if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
// tmp_path should have the same length as java_home_len, since we only
// replaced 'jre' with 'bin'
if (len > (int)java_home_len + 1) {
strncat(paths, os::path_separator(), 1);
strncat(paths, tmp_path, java_home_len);
}
}
}
WindowsDbgHelp::symSetSearchPath(hProcess, paths);
// find out if jvm.dll contains private symbols, by decoding
// current function and comparing the result
address addr = (address)Decoder::demangle;
char buf[MAX_PATH];
if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
_can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
}
} }
} }
void WindowsDecoder::uninitialize() { void WindowsDecoder::uninitialize() {}
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
#ifdef AMD64
_pfnStackWalk64 = NULL;
_pfnSymFunctionTableAccess64 = NULL;
_pfnSymGetModuleBase64 = NULL;
#endif
if (_dbghelp_handle != NULL) {
::FreeLibrary(_dbghelp_handle);
}
_dbghelp_handle = NULL;
}
bool WindowsDecoder::can_decode_C_frame_in_vm() const { bool WindowsDecoder::can_decode_C_frame_in_vm() const {
return (!has_error() && _can_decode_in_vm); return (!has_error() && _can_decode_in_vm);
@ -188,14 +127,14 @@ bool WindowsDecoder::can_decode_C_frame_in_vm() const {
bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) { bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) {
if (_pfnSymGetSymFromAddr64 != NULL) { if (!has_error()) {
PIMAGEHLP_SYMBOL64 pSymbol; PIMAGEHLP_SYMBOL64 pSymbol;
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)]; char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo; pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
pSymbol->MaxNameLength = MAX_PATH; pSymbol->MaxNameLength = MAX_PATH;
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD64 displacement; DWORD64 displacement;
if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
if (buf != NULL) { if (buf != NULL) {
if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) { if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", pSymbol->Name); jio_snprintf(buf, buflen, "%s", pSymbol->Name);
@ -211,69 +150,9 @@ bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, co
} }
bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) { bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
return _pfnUndecorateSymbolName != NULL && if (!has_error()) {
_pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE); return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
}
#ifdef AMD64
BOOL WindowsDbgHelp::StackWalk64(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) {
DecoderLocker locker;
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
if (!wd->has_error() && wd->_pfnStackWalk64) {
return wd->_pfnStackWalk64(MachineType,
hProcess,
hThread,
StackFrame,
ContextRecord,
ReadMemoryRoutine,
FunctionTableAccessRoutine,
GetModuleBaseRoutine,
TranslateAddress);
} else {
return false;
} }
return false;
} }
PVOID WindowsDbgHelp::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
DecoderLocker locker;
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
if (!wd->has_error() && wd->_pfnSymFunctionTableAccess64) {
return wd->_pfnSymFunctionTableAccess64(hProcess, AddrBase);
} else {
return NULL;
}
}
pfn_SymFunctionTableAccess64 WindowsDbgHelp::pfnSymFunctionTableAccess64() {
DecoderLocker locker;
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
if (!wd->has_error()) {
return wd->_pfnSymFunctionTableAccess64;
} else {
return NULL;
}
}
pfn_SymGetModuleBase64 WindowsDbgHelp::pfnSymGetModuleBase64() {
DecoderLocker locker;
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
if (!wd->has_error()) {
return wd->_pfnSymGetModuleBase64;
} else {
return NULL;
}
}
#endif // AMD64

@ -25,33 +25,8 @@
#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP #ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP
#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP #define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP
#include <windows.h>
#include <imagehlp.h>
#include "utilities/decoder.hpp" #include "utilities/decoder.hpp"
// functions needed for decoding symbols
typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD);
typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
#ifdef AMD64
typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
#endif
class WindowsDecoder : public AbstractDecoder { class WindowsDecoder : public AbstractDecoder {
public: public:
@ -70,38 +45,8 @@ private:
void initialize(); void initialize();
void uninitialize(); void uninitialize();
private:
HMODULE _dbghelp_handle;
bool _can_decode_in_vm; bool _can_decode_in_vm;
pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64;
pfn_UndecorateSymbolName _pfnUndecorateSymbolName;
#ifdef AMD64
pfn_StackWalk64 _pfnStackWalk64;
pfn_SymFunctionTableAccess64 _pfnSymFunctionTableAccess64;
pfn_SymGetModuleBase64 _pfnSymGetModuleBase64;
friend class WindowsDbgHelp;
#endif
}; };
#ifdef AMD64
// TODO: refactor and move the handling of dbghelp.dll outside of Decoder
class WindowsDbgHelp : public Decoder {
public:
static BOOL StackWalk64(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
static PVOID SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
static pfn_SymFunctionTableAccess64 pfnSymFunctionTableAccess64();
static pfn_SymGetModuleBase64 pfnSymGetModuleBase64();
};
#endif
#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP #endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP

@ -74,6 +74,8 @@
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#include "windbghelp.hpp"
#ifdef _DEBUG #ifdef _DEBUG
#include <crtdbg.h> #include <crtdbg.h>
@ -1009,7 +1011,6 @@ void os::check_dump_limit(char* buffer, size_t buffsz) {
} }
void os::abort(bool dump_core, void* siginfo, const void* context) { void os::abort(bool dump_core, void* siginfo, const void* context) {
HINSTANCE dbghelp;
EXCEPTION_POINTERS ep; EXCEPTION_POINTERS ep;
MINIDUMP_EXCEPTION_INFORMATION mei; MINIDUMP_EXCEPTION_INFORMATION mei;
MINIDUMP_EXCEPTION_INFORMATION* pmei; MINIDUMP_EXCEPTION_INFORMATION* pmei;
@ -1026,28 +1027,6 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
win32::exit_process_or_thread(win32::EPT_PROCESS, 1); win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
} }
dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0);
if (dbghelp == NULL) {
jio_fprintf(stderr, "Failed to load dbghelp.dll\n");
CloseHandle(dumpFile);
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
}
_MiniDumpWriteDump =
CAST_TO_FN_PTR(BOOL(WINAPI *)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
PMINIDUMP_EXCEPTION_INFORMATION,
PMINIDUMP_USER_STREAM_INFORMATION,
PMINIDUMP_CALLBACK_INFORMATION),
GetProcAddress(dbghelp,
"MiniDumpWriteDump"));
if (_MiniDumpWriteDump == NULL) {
jio_fprintf(stderr, "Failed to find MiniDumpWriteDump() in module dbghelp.dll.\n");
CloseHandle(dumpFile);
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
}
dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData | dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData |
MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules); MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules);
@ -1064,8 +1043,8 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
// Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all
// the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then.
if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false && if (!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) &&
_MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) { !WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL)) {
jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError()); jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError());
} }
CloseHandle(dumpFile); CloseHandle(dumpFile);
@ -1198,70 +1177,6 @@ const char* os::get_temp_directory() {
} }
} }
static bool file_exists(const char* filename) {
if (filename == NULL || strlen(filename) == 0) {
return false;
}
return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
}
bool os::dll_build_name(char *buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
const size_t pnamelen = pname ? strlen(pname) : 0;
const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > buflen) {
return retval;
}
if (pnamelen == 0) {
jio_snprintf(buffer, buflen, "%s.dll", fname);
retval = true;
} else if (c == ':' || c == '\\') {
jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
if (pelements == NULL) {
return false;
}
for (int i = 0; i < n; i++) {
char* path = pelements[i];
// Really shouldn't be NULL, but check can't hurt
size_t plen = (path == NULL) ? 0 : strlen(path);
if (plen == 0) {
continue; // skip the empty path values
}
const char lastchar = path[plen - 1];
if (lastchar == ':' || lastchar == '\\') {
jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
} else {
jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
}
if (file_exists(buffer)) {
retval = true;
break;
}
}
// release the storage
for (int i = 0; i < n; i++) {
if (pelements[i] != NULL) {
FREE_C_HEAP_ARRAY(char, pelements[i]);
}
}
if (pelements != NULL) {
FREE_C_HEAP_ARRAY(char*, pelements);
}
} else {
jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
retval = true;
}
return retval;
}
// Needs to be in os specific directory because windows requires another // Needs to be in os specific directory because windows requires another
// header file <direct.h> // header file <direct.h>
const char* os::get_current_directory(char *buf, size_t buflen) { const char* os::get_current_directory(char *buf, size_t buflen) {
@ -3591,22 +3506,6 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
return interrupted; return interrupted;
} }
// Get's a pc (hint) for a running thread. Currently used only for profiling.
ExtendedPC os::get_thread_pc(Thread* thread) {
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
HANDLE handle = thread->osthread()->thread_handle();
if (GetThreadContext(handle, &context)) {
#ifdef _M_AMD64
return ExtendedPC((address) context.Rip);
#else
return ExtendedPC((address) context.Eip);
#endif
} else {
return ExtendedPC(NULL);
}
}
// GetCurrentThreadId() returns DWORD // GetCurrentThreadId() returns DWORD
intx os::current_thread_id() { return GetCurrentThreadId(); } intx os::current_thread_id() { return GetCurrentThreadId(); }

@ -0,0 +1,306 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "utilities/ostream.hpp"
#include "windbghelp.hpp"
#include <windows.h>
typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
typedef DWORD (WINAPI *pfn_SymGetOptions)(void);
typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
typedef DWORD (WINAPI *pfn_UnDecorateSymbolName)(const char*, char*, DWORD, DWORD);
typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
typedef BOOL (WINAPI *pfn_MiniDumpWriteDump) (HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
typedef BOOL (WINAPI *pfn_SymGetLineFromAddr64) (HANDLE hProcess, DWORD64 dwAddr,
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
typedef LPAPI_VERSION (WINAPI *pfn_ImagehlpApiVersion)(void);
// Add functions as needed.
#define FOR_ALL_FUNCTIONS(DO) \
DO(ImagehlpApiVersion) \
DO(SymGetOptions) \
DO(SymSetOptions) \
DO(SymInitialize) \
DO(SymGetSymFromAddr64) \
DO(UnDecorateSymbolName) \
DO(SymSetSearchPath) \
DO(SymGetSearchPath) \
DO(StackWalk64) \
DO(SymFunctionTableAccess64) \
DO(SymGetModuleBase64) \
DO(MiniDumpWriteDump) \
DO(SymGetLineFromAddr64)
#define DECLARE_FUNCTION_POINTER(functionname) \
static pfn_##functionname g_pfn_##functionname;
FOR_ALL_FUNCTIONS(DECLARE_FUNCTION_POINTER)
static HMODULE g_dll_handle = NULL;
static DWORD g_dll_load_error = 0;
static API_VERSION g_version = { 0, 0, 0, 0 };
static enum {
state_uninitialized = 0,
state_ready = 1,
state_error = 2
} g_state = state_uninitialized;
static void initialize() {
assert(g_state == state_uninitialized, "wrong sequence");
g_state = state_error;
g_dll_handle = ::LoadLibrary("DBGHELP.DLL");
if (g_dll_handle == NULL) {
g_dll_load_error = ::GetLastError();
} else {
// Note: We loaded the DLL successfully. From here on we count
// initialization as success. We still may fail to load all of the
// desired function pointers successfully, but DLL may still be usable
// enough for our purposes.
g_state = state_ready;
#define DO_RESOLVE(functionname) \
g_pfn_##functionname = (pfn_##functionname) ::GetProcAddress(g_dll_handle, #functionname);
FOR_ALL_FUNCTIONS(DO_RESOLVE)
// Retrieve version information.
if (g_pfn_ImagehlpApiVersion) {
const API_VERSION* p = g_pfn_ImagehlpApiVersion();
memcpy(&g_version, p, sizeof(API_VERSION));
}
}
}
///////////////////// External functions //////////////////////////
// All outside facing functions are synchronized. Also, we run
// initialization on first touch.
// Call InitializeCriticalSection as early as possible.
class CritSect {
CRITICAL_SECTION cs;
public:
CritSect() { ::InitializeCriticalSection(&cs); }
void enter() { ::EnterCriticalSection(&cs); }
void leave() { ::LeaveCriticalSection(&cs); }
};
static CritSect g_cs;
class EntryGuard {
public:
EntryGuard() {
g_cs.enter();
if (g_state == state_uninitialized) {
initialize();
}
}
~EntryGuard() {
g_cs.leave();
}
};
DWORD WindowsDbgHelp::symSetOptions(DWORD arg) {
EntryGuard entry_guard;
if (g_pfn_SymSetOptions != NULL) {
return g_pfn_SymSetOptions(arg);
}
return 0;
}
DWORD WindowsDbgHelp::symGetOptions(void) {
EntryGuard entry_guard;
if (g_pfn_SymGetOptions != NULL) {
return g_pfn_SymGetOptions();
}
return 0;
}
BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL fInvadeProcess) {
EntryGuard entry_guard;
if (g_pfn_SymInitialize != NULL) {
return g_pfn_SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
}
return FALSE;
}
BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address,
PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) {
EntryGuard entry_guard;
if (g_pfn_SymGetSymFromAddr64 != NULL) {
return g_pfn_SymGetSymFromAddr64(hProcess, the_address, Displacement, Symbol);
}
return FALSE;
}
DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDecoratedName,
DWORD UndecoratedLength, DWORD Flags) {
EntryGuard entry_guard;
if (g_pfn_UnDecorateSymbolName != NULL) {
return g_pfn_UnDecorateSymbolName(DecoratedName, UnDecoratedName, UndecoratedLength, Flags);
}
if (UnDecoratedName != NULL && UndecoratedLength > 0) {
UnDecoratedName[0] = '\0';
}
return 0;
}
BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) {
EntryGuard entry_guard;
if (g_pfn_SymSetSearchPath != NULL) {
return g_pfn_SymSetSearchPath(hProcess, SearchPath);
}
return FALSE;
}
BOOL WindowsDbgHelp::symGetSearchPath(HANDLE hProcess, PTSTR SearchPath, int SearchPathLength) {
EntryGuard entry_guard;
if (g_pfn_SymGetSearchPath != NULL) {
return g_pfn_SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
}
return FALSE;
}
BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord) {
EntryGuard entry_guard;
if (g_pfn_StackWalk64 != NULL) {
return g_pfn_StackWalk64(MachineType, hProcess, hThread, StackFrame,
ContextRecord,
NULL, // ReadMemoryRoutine
g_pfn_SymFunctionTableAccess64, // FunctionTableAccessRoutine,
g_pfn_SymGetModuleBase64, // GetModuleBaseRoutine
NULL // TranslateAddressRoutine
);
}
return FALSE;
}
PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
EntryGuard entry_guard;
if (g_pfn_SymFunctionTableAccess64 != NULL) {
return g_pfn_SymFunctionTableAccess64(hProcess, AddrBase);
}
return NULL;
}
DWORD64 WindowsDbgHelp::symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) {
EntryGuard entry_guard;
if (g_pfn_SymGetModuleBase64 != NULL) {
return g_pfn_SymGetModuleBase64(hProcess, dwAddr);
}
return 0;
}
BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam) {
EntryGuard entry_guard;
if (g_pfn_MiniDumpWriteDump != NULL) {
return g_pfn_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType,
ExceptionParam, UserStreamParam, CallbackParam);
}
return FALSE;
}
BOOL WindowsDbgHelp::symGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) {
EntryGuard entry_guard;
if (g_pfn_SymGetLineFromAddr64 != NULL) {
return g_pfn_SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, Line);
}
return FALSE;
}
// Print one liner describing state (if library loaded, which functions are
// missing - if any, and the dbhelp API version)
void WindowsDbgHelp::print_state_on(outputStream* st) {
// Note: We should not lock while printing, but this should be
// safe to do without lock anyway.
st->print("dbghelp: ");
if (g_state == state_uninitialized) {
st->print("uninitialized.");
} else if (g_state == state_error) {
st->print("loading error: %u", g_dll_load_error);
} else {
st->print("loaded successfully ");
// We may want to print dll file name here - which may be interesting for
// cases where more than one version exists on the system, e.g. with a
// debugging sdk separately installed. But we get the file name in the DLL
// section of the hs-err file too, so this may be redundant.
// Print version.
st->print("- version: %u.%u.%u",
g_version.MajorVersion, g_version.MinorVersion, g_version.Revision);
// Print any functions which failed to load.
int num_missing = 0;
st->print(" - missing functions: ");
#define CHECK_AND_PRINT_IF_NULL(functionname) \
if (g_pfn_##functionname == NULL) { \
st->print("%s" #functionname, ((num_missing > 0) ? ", " : "")); \
num_missing ++; \
}
FOR_ALL_FUNCTIONS(CHECK_AND_PRINT_IF_NULL)
if (num_missing == 0) {
st->print("none");
}
}
st->cr();
}

@ -0,0 +1,73 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef OS_WINDOWS_VM_DBGHELPLOADER_HPP
#define OS_WINDOWS_VM_DBGHELPLOADER_HPP
#include <windows.h>
#include <imagehlp.h>
// This is a very plain wrapper for loading dbghelp.dll. It does not offer
// any additional functionality. It takes care of locking.
class outputStream;
// Please note: dbghelp.dll may not have been loaded, or it may have been loaded but not
// all functions may be available (because on the target system dbghelp.dll is of an
// older version).
// In all these cases we return an error from the WindowsDbgHelp::symXXXX() wrapper. We never
// assert. It should always be safe to call these functions, but caller has to process the
// return code (which he would have to do anyway).
namespace WindowsDbgHelp {
DWORD symSetOptions(DWORD);
DWORD symGetOptions(void);
BOOL symInitialize(HANDLE, PCTSTR, BOOL);
BOOL symGetSymFromAddr64(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
DWORD unDecorateSymbolName(const char*, char*, DWORD, DWORD);
BOOL symSetSearchPath(HANDLE, PCTSTR);
BOOL symGetSearchPath(HANDLE, PTSTR, int);
BOOL stackWalk64(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord);
PVOID symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
DWORD64 symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr);
BOOL miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
BOOL symGetLineFromAddr64 (HANDLE hProcess, DWORD64 dwAddr,
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
// Print one liner describing state (if library loaded, which functions are
// missing - if any, and the dbhelp API version)
void print_state_on(outputStream* st);
};
#endif // OS_WINDOWS_VM_DBGHELPLOADER_HPP

@ -106,8 +106,8 @@ struct Atomic::PlatformAdd
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(I));
STATIC_CAST(4 == sizeof(D)); STATIC_ASSERT(4 == sizeof(D));
D result; D result;
@ -129,8 +129,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(I));
STATIC_CAST(8 == sizeof(D)); STATIC_ASSERT(8 == sizeof(D));
D result; D result;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -29,7 +29,6 @@
private: private:
void pd_initialize() { void pd_initialize() {
_anchor.clear(); _anchor.clear();
_last_interpreter_fp = NULL;
} }
// The `last' frame is the youngest Java frame on the thread's stack. // The `last' frame is the youngest Java frame on the thread's stack.
@ -60,20 +59,4 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava); bool isInJava);
// -Xprof support
//
// In order to find the last Java fp from an async profile
// tick, we store the current interpreter fp in the thread.
// This value is only valid while we are in the C++ interpreter
// and profiling.
protected:
intptr_t *_last_interpreter_fp;
public:
static ByteSize last_interpreter_fp_offset() {
return byte_offset_of(JavaThread, _last_interpreter_fp);
}
intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
#endif // OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP #endif // OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP

@ -184,8 +184,8 @@ struct Atomic::PlatformAdd
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(I));
STATIC_CAST(4 == sizeof(D)); STATIC_ASSERT(4 == sizeof(D));
#ifdef ARM #ifdef ARM
return add_using_helper<int>(arm_add_and_fetch, add_value, dest); return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
@ -201,8 +201,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(I));
STATIC_CAST(8 == sizeof(D)); STATIC_ASSERT(8 == sizeof(D));
return __sync_add_and_fetch(dest, add_value); return __sync_add_and_fetch(dest, add_value);
} }
@ -283,7 +283,7 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
T volatile* dest, T volatile* dest,
T compare_value, T compare_value,
cmpxchg_memory_order order) const { cmpxchg_memory_order order) const {
STATIC_CAST(4 == sizeof(T)); STATIC_ASSERT(4 == sizeof(T));
#ifdef ARM #ifdef ARM
return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value); return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value);
#else #else
@ -301,7 +301,7 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
T volatile* dest, T volatile* dest,
T compare_value, T compare_value,
cmpxchg_memory_order order) const { cmpxchg_memory_order order) const {
STATIC_CAST(8 == sizeof(T)); STATIC_ASSERT(8 == sizeof(T));
return __sync_val_compare_and_swap(dest, compare_value, exchange_value); return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
} }

@ -104,8 +104,8 @@ struct Atomic::PlatformAdd
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(I));
STATIC_CAST(4 == sizeof(D)); STATIC_ASSERT(4 == sizeof(D));
D result; D result;
@ -127,8 +127,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(I));
STATIC_CAST(8 == sizeof(D)); STATIC_ASSERT(8 == sizeof(D));
D result; D result;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -30,7 +30,6 @@
void pd_initialize() { void pd_initialize() {
_anchor.clear(); _anchor.clear();
_last_interpreter_fp = NULL;
} }
// The `last' frame is the youngest Java frame on the thread's stack. // The `last' frame is the youngest Java frame on the thread's stack.
@ -62,22 +61,4 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
protected:
// -Xprof support
//
// In order to find the last Java fp from an async profile
// tick, we store the current interpreter fp in the thread.
// This value is only valid while we are in the C++ interpreter
// and profiling.
intptr_t *_last_interpreter_fp;
public:
static ByteSize last_interpreter_fp_offset() {
return byte_offset_of(JavaThread, _last_interpreter_fp);
}
intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
#endif // OS_CPU_LINUX_PPC_VM_THREAD_LINUX_PPC_HPP #endif // OS_CPU_LINUX_PPC_VM_THREAD_LINUX_PPC_HPP

@ -92,9 +92,9 @@ struct Atomic::PlatformAdd
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<4>::add_and_fetch(I inc, D volatile* dest) const {
STATIC_CAST(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(I));
STATIC_CAST(4 == sizeof(D)); STATIC_ASSERT(4 == sizeof(D));
D old, upd; D old, upd;
@ -143,9 +143,9 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<8>::add_and_fetch(I inc, D volatile* dest) const {
STATIC_CAST(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(I));
STATIC_CAST(8 == sizeof(D)); STATIC_ASSERT(8 == sizeof(D));
D old, upd; D old, upd;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -30,7 +30,6 @@
void pd_initialize() { void pd_initialize() {
_anchor.clear(); _anchor.clear();
_last_interpreter_fp = NULL;
} }
// The `last' frame is the youngest Java frame on the thread's stack. // The `last' frame is the youngest Java frame on the thread's stack.
@ -61,22 +60,4 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
protected:
// -Xprof support
//
// In order to find the last Java fp from an async profile
// tick, we store the current interpreter fp in the thread.
// This value is only valid while we are in the C++ interpreter
// and profiling.
intptr_t *_last_interpreter_fp;
public:
static ByteSize last_interpreter_fp_offset() {
return byte_offset_of(JavaThread, _last_interpreter_fp);
}
intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
#endif // OS_CPU_LINUX_S390_VM_THREAD_LINUX_S390_HPP #endif // OS_CPU_LINUX_S390_VM_THREAD_LINUX_S390_HPP

@ -62,8 +62,8 @@ struct Atomic::PlatformAdd
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(I));
STATIC_CAST(4 == sizeof(D)); STATIC_ASSERT(4 == sizeof(D));
D rv; D rv;
__asm__ volatile( __asm__ volatile(
@ -81,10 +81,11 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
return rv; return rv;
} }
template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(I));
STATIC_CAST(8 == sizeof(D)); STATIC_ASSERT(8 == sizeof(D));
D rv; D rv;
__asm__ volatile( __asm__ volatile(

@ -178,8 +178,8 @@ struct Atomic::PlatformAdd
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(I));
STATIC_CAST(4 == sizeof(D)); STATIC_ASSERT(4 == sizeof(D));
#ifdef ARM #ifdef ARM
return add_using_helper<int>(arm_add_and_fetch, add_value, dest); return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
@ -195,8 +195,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
template<> template<>
template<typename I, typename D> template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
STATIC_CAST(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(I));
STATIC_CAST(8 == sizeof(D)); STATIC_ASSERT(8 == sizeof(D));
return __sync_add_and_fetch(dest, add_value); return __sync_add_and_fetch(dest, add_value);
} }

@ -29,7 +29,6 @@
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "code/icBuffer.hpp" #include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "decoder_windows.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "jvm_windows.h" #include "jvm_windows.h"
#include "memory/allocation.inline.hpp" #include "memory/allocation.inline.hpp"
@ -51,10 +50,12 @@
#include "runtime/stubRoutines.hpp" #include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp" #include "runtime/timer.hpp"
#include "unwind_windows_x86.hpp"
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#include "windbghelp.hpp"
# include "unwind_windows_x86.hpp"
#undef REG_SP #undef REG_SP
#undef REG_FP #undef REG_FP
#undef REG_PC #undef REG_PC
@ -401,24 +402,18 @@ bool os::platform_print_native_stack(outputStream* st, const void* context,
lastpc = pc; lastpc = pc;
} }
PVOID p = WindowsDbgHelp::SymFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset); PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
if (!p) { if (!p) {
// StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash. // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
break; break;
} }
BOOL result = WindowsDbgHelp::StackWalk64( BOOL result = WindowsDbgHelp::stackWalk64(
IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType, IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
GetCurrentProcess(), // __in HANDLE hProcess, GetCurrentProcess(), // __in HANDLE hProcess,
GetCurrentThread(), // __in HANDLE hThread, GetCurrentThread(), // __in HANDLE hThread,
&stk, // __inout LP STACKFRAME64 StackFrame, &stk, // __inout LP STACKFRAME64 StackFrame,
&ctx, // __inout PVOID ContextRecord, &ctx); // __inout PVOID ContextRecord,
NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
WindowsDbgHelp::pfnSymFunctionTableAccess64(),
// __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
WindowsDbgHelp::pfnSymGetModuleBase64(),
// __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
NULL); // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
if (!result) { if (!result) {
break; break;

@ -12,7 +12,6 @@
-Xms<size> set initial Java heap size -Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size -Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size -Xss<size> set java thread stack size
-Xprof output cpu profiling data (deprecated)
-Xfuture enable strictest checks, anticipating future default -Xfuture enable strictest checks, anticipating future default
-Xrs reduce use of OS signals by Java/VM (see documentation) -Xrs reduce use of OS signals by Java/VM (see documentation)
-Xcheck:jni perform additional checks for JNI functions -Xcheck:jni perform additional checks for JNI functions

@ -478,6 +478,8 @@ void AOTCodeHeap::link_stub_routines_symbols() {
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_unsafe_arraycopy", address, StubRoutines::_unsafe_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);

@ -57,7 +57,6 @@
#include "prims/jvm_misc.hpp" #include "prims/jvm_misc.hpp"
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/compilationPolicy.hpp" #include "runtime/compilationPolicy.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.hpp" #include "runtime/handles.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/init.hpp" #include "runtime/init.hpp"
@ -147,6 +146,7 @@ ClassPathEntry* ClassLoader::_jrt_entry = NULL;
ClassPathEntry* ClassLoader::_first_append_entry = NULL; ClassPathEntry* ClassLoader::_first_append_entry = NULL;
ClassPathEntry* ClassLoader::_last_append_entry = NULL; ClassPathEntry* ClassLoader::_last_append_entry = NULL;
int ClassLoader::_num_entries = 0; int ClassLoader::_num_entries = 0;
int ClassLoader::_num_boot_entries = -1;
#if INCLUDE_CDS #if INCLUDE_CDS
GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL; GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL; GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
@ -242,7 +242,7 @@ const char* ClassLoader::package_from_name(const char* const class_name, bool* b
// Given a fully qualified class name, find its defining package in the class loader's // Given a fully qualified class name, find its defining package in the class loader's
// package entry table. // package entry table.
static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) { PackageEntry* ClassLoader::get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
const char *pkg_name = ClassLoader::package_from_name(class_name); const char *pkg_name = ClassLoader::package_from_name(class_name);
if (pkg_name == NULL) { if (pkg_name == NULL) {
@ -509,7 +509,7 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
#endif #endif
} else { } else {
PackageEntry* package_entry = get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL); PackageEntry* package_entry = ClassLoader::get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
if (package_entry != NULL) { if (package_entry != NULL) {
ResourceMark rm; ResourceMark rm;
// Get the module name // Get the module name
@ -540,6 +540,13 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
return NULL; return NULL;
} }
JImageLocationRef ClassLoader::jimage_find_resource(JImageFile* jf,
const char* module_name,
const char* file_name,
jlong &size) {
return ((*JImageFindResource)(jf, module_name, get_jimage_version_string(), file_name, &size));
}
#ifndef PRODUCT #ifndef PRODUCT
bool ctw_visitor(JImageFile* jimage, bool ctw_visitor(JImageFile* jimage,
const char* module_name, const char* version, const char* package, const char* module_name, const char* version, const char* package,
@ -1066,7 +1073,7 @@ void ClassLoader::load_zip_library() {
char path[JVM_MAXPATHLEN]; char path[JVM_MAXPATHLEN];
char ebuf[1024]; char ebuf[1024];
void* handle = NULL; void* handle = NULL;
if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip")) { if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
handle = os::dll_load(path, ebuf, sizeof ebuf); handle = os::dll_load(path, ebuf, sizeof ebuf);
} }
if (handle == NULL) { if (handle == NULL) {
@ -1104,7 +1111,7 @@ void ClassLoader::load_jimage_library() {
char path[JVM_MAXPATHLEN]; char path[JVM_MAXPATHLEN];
char ebuf[1024]; char ebuf[1024];
void* handle = NULL; void* handle = NULL;
if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "jimage")) { if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "jimage")) {
handle = os::dll_load(path, ebuf, sizeof ebuf); handle = os::dll_load(path, ebuf, sizeof ebuf);
} }
if (handle == NULL) { if (handle == NULL) {
@ -1434,7 +1441,6 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
const char* const class_name = name->as_C_string(); const char* const class_name = name->as_C_string();
EventMark m("loading class %s", class_name); EventMark m("loading class %s", class_name);
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
const char* const file_name = file_name_for_class_name(class_name, const char* const file_name = file_name_for_class_name(class_name,
name->utf8_length()); name->utf8_length());
@ -1459,9 +1465,6 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
// This would include: // This would include:
// [--patch-module=<module>=<file>(<pathsep><file>)*]; [jimage | exploded module build] // [--patch-module=<module>=<file>(<pathsep><file>)*]; [jimage | exploded module build]
// //
// DumpSharedSpaces and search_append_only are mutually exclusive and cannot
// be true at the same time.
assert(!(DumpSharedSpaces && search_append_only), "DumpSharedSpaces and search_append_only are both true");
// Load Attempt #1: --patch-module // Load Attempt #1: --patch-module
// Determine the class' defining module. If it appears in the _patch_mod_entries, // Determine the class' defining module. If it appears in the _patch_mod_entries,
@ -1507,6 +1510,11 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
e = _first_append_entry; e = _first_append_entry;
while (e != NULL) { while (e != NULL) {
if (DumpSharedSpaces && classpath_index >= _num_boot_entries) {
// Do not load any class from the app classpath using the boot loader. Let
// the built-in app class laoder load them.
break;
}
stream = e->open_stream(file_name, CHECK_NULL); stream = e->open_stream(file_name, CHECK_NULL);
if (!context.check(stream, classpath_index)) { if (!context.check(stream, classpath_index)) {
return NULL; return NULL;
@ -1520,9 +1528,6 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
} }
if (NULL == stream) { if (NULL == stream) {
if (DumpSharedSpaces) {
tty->print_cr("Preload Warning: Cannot find %s", class_name);
}
return NULL; return NULL;
} }
@ -1548,6 +1553,100 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
return context.record_result(name, e, classpath_index, result, THREAD); return context.record_result(name, e, classpath_index, result, THREAD);
} }
#if INCLUDE_CDS
static char* skip_uri_protocol(char* source) {
if (strncmp(source, "file:", 5) == 0) {
// file: protocol path could start with file:/ or file:///
// locate the char after all the forward slashes
int offset = 5;
while (*(source + offset) == '/') {
offset++;
}
source += offset;
// for non-windows platforms, move back one char as the path begins with a '/'
#ifndef _WINDOWS
source -= 1;
#endif
} else if (strncmp(source, "jrt:/", 5) == 0) {
source += 5;
}
return source;
}
void ClassLoader::record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream) {
assert(DumpSharedSpaces, "sanity");
assert(stream != NULL, "sanity");
if (ik->is_anonymous()) {
// We do not archive anonymous classes.
return;
}
if (stream->source() == NULL) {
if (ik->class_loader() == NULL) {
// JFR classes
ik->set_shared_classpath_index(0);
ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
}
return;
}
assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
ModuleEntry* module = ik->module();
ClassPathEntry* e = NULL;
int classpath_index = 0;
// Check if the class is from the runtime image
if (module != NULL && (module->location() != NULL) &&
(module->location()->starts_with("jrt:"))) {
e = _jrt_entry;
classpath_index = 0;
} else {
classpath_index = 1;
ResourceMark rm;
char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
for (e = _first_append_entry; e != NULL; e = e->next()) {
if (get_canonical_path(e->name(), canonical_path, JVM_MAXPATHLEN)) {
char* src = (char*)stream->source();
// save the path from the file: protocol or the module name from the jrt: protocol
// if no protocol prefix is found, src is the same as stream->source() after the following call
src = skip_uri_protocol(src);
if (strcmp(canonical_path, os::native_path((char*)src)) == 0) {
break;
}
classpath_index ++;
}
}
if (e == NULL) {
assert(ik->shared_classpath_index() < 0,
"must be a class from a custom jar which isn't in the class path or boot class path");
return;
}
}
if (classpath_index < _num_boot_entries) {
// ik is either:
// 1) a boot class loaded from the runtime image during vm initialization (classpath_index = 0); or
// 2) a user's class from -Xbootclasspath/a (classpath_index > 0)
// In the second case, the classpath_index, classloader_type will be recorded via
// context.record_result() in ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS).
if (classpath_index > 0) {
return;
}
}
ResourceMark rm;
const char* const class_name = ik->name()->as_C_string();
const char* const file_name = file_name_for_class_name(class_name,
ik->name()->utf8_length());
assert(file_name != NULL, "invariant");
Thread* THREAD = Thread::current();
ClassLoaderExt::Context context(class_name, file_name, CATCH);
context.record_result(ik->name(), e, classpath_index, ik, THREAD);
}
#endif // INCLUDE_CDS
// Initialize the class loader's access to methods in libzip. Parse and // Initialize the class loader's access to methods in libzip. Parse and
// process the boot classpath into a list ClassPathEntry objects. Once // process the boot classpath into a list ClassPathEntry objects. Once
// this list has been created, it must not change order (see class PackageInfo) // this list has been created, it must not change order (see class PackageInfo)
@ -1632,6 +1731,7 @@ void ClassLoader::initialize() {
#if INCLUDE_CDS #if INCLUDE_CDS
void ClassLoader::initialize_shared_path() { void ClassLoader::initialize_shared_path() {
if (DumpSharedSpaces) { if (DumpSharedSpaces) {
_num_boot_entries = _num_entries;
ClassLoaderExt::setup_search_paths(); ClassLoaderExt::setup_search_paths();
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check() _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
} }

@ -25,6 +25,7 @@
#ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP #ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP #define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#include "classfile/jimage.hpp"
#include "runtime/orderAccess.hpp" #include "runtime/orderAccess.hpp"
#include "runtime/perfData.hpp" #include "runtime/perfData.hpp"
#include "utilities/exceptions.hpp" #include "utilities/exceptions.hpp"
@ -47,6 +48,7 @@
class JImageFile; class JImageFile;
class ClassFileStream; class ClassFileStream;
class PackageEntry;
class ClassPathEntry : public CHeapObj<mtClass> { class ClassPathEntry : public CHeapObj<mtClass> {
private: private:
@ -103,7 +105,6 @@ typedef struct {
jlong pos; /* position of LOC header (if negative) or data */ jlong pos; /* position of LOC header (if negative) or data */
} jzentry; } jzentry;
class ClassPathZipEntry: public ClassPathEntry { class ClassPathZipEntry: public ClassPathEntry {
enum { enum {
_unknown = 0, _unknown = 0,
@ -249,6 +250,10 @@ class ClassLoader: AllStatic {
// the entries on the _first_append_entry linked list. // the entries on the _first_append_entry linked list.
static int _num_entries; static int _num_entries;
// number of entries in the boot class path including the
// java runtime image
static int _num_boot_entries;
// Array of module names associated with the boot class loader // Array of module names associated with the boot class loader
CDS_ONLY(static GrowableArray<char*>* _boot_modules_array;) CDS_ONLY(static GrowableArray<char*>* _boot_modules_array;)
@ -289,6 +294,7 @@ class ClassLoader: AllStatic {
static bool get_canonical_path(const char* orig, char* out, int len); static bool get_canonical_path(const char* orig, char* out, int len);
static const char* file_name_for_class_name(const char* class_name, static const char* file_name_for_class_name(const char* class_name,
int class_name_len); int class_name_len);
static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS);
public: public:
static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg); static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
@ -436,7 +442,10 @@ class ClassLoader: AllStatic {
static void initialize_module_loader_map(JImageFile* jimage); static void initialize_module_loader_map(JImageFile* jimage);
static s2 classloader_type(Symbol* class_name, ClassPathEntry* e, static s2 classloader_type(Symbol* class_name, ClassPathEntry* e,
int classpath_index, TRAPS); int classpath_index, TRAPS);
static void record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream);
#endif #endif
static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
const char* file_name, jlong &size);
static void trace_class_path(const char* msg, const char* name = NULL); static void trace_class_path(const char* msg, const char* name = NULL);

@ -75,6 +75,9 @@
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/ostream.hpp" #include "utilities/ostream.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#endif // INCLUDE_ALL_GCS
#if INCLUDE_TRACE #if INCLUDE_TRACE
#include "trace/tracing.hpp" #include "trace/tracing.hpp"
#endif #endif
@ -764,6 +767,25 @@ OopHandle ClassLoaderData::add_handle(Handle h) {
return OopHandle(_handles.add(h())); return OopHandle(_handles.add(h()));
} }
void ClassLoaderData::remove_handle(OopHandle h) {
oop* ptr = h.ptr_raw();
if (ptr != NULL) {
assert(_handles.contains(ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr));
#if INCLUDE_ALL_GCS
// This barrier is used by G1 to remember the old oop values, so
// that we don't forget any objects that were live at the snapshot at
// the beginning.
if (UseG1GC) {
oop obj = *ptr;
if (obj != NULL) {
G1SATBCardTableModRefBS::enqueue(obj);
}
}
#endif
*ptr = NULL;
}
}
void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) { void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
if (dest.resolve() != NULL) { if (dest.resolve() != NULL) {

@ -364,6 +364,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
const char* loader_name(); const char* loader_name();
OopHandle add_handle(Handle h); OopHandle add_handle(Handle h);
void remove_handle(OopHandle h);
void init_handle_locked(OopHandle& pd, Handle h); // used for concurrent access to ModuleEntry::_pd field void init_handle_locked(OopHandle& pd, Handle h); // used for concurrent access to ModuleEntry::_pd field
void add_class(Klass* k, bool publicize = true); void add_class(Klass* k, bool publicize = true);
void remove_class(Klass* k); void remove_class(Klass* k);

@ -26,6 +26,7 @@
#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP #define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
#include "classfile/classLoader.hpp" #include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "runtime/handles.hpp" #include "runtime/handles.hpp"
@ -56,8 +57,15 @@ public:
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) { if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
#if INCLUDE_CDS #if INCLUDE_CDS
if (DumpSharedSpaces) { if (DumpSharedSpaces) {
s2 classloader_type = ClassLoader::classloader_type( oop loader = result->class_loader();
class_name, e, classpath_index, CHECK_(result)); s2 classloader_type = ClassLoader::BOOT_LOADER;
if (SystemDictionary::is_system_class_loader(loader)) {
classloader_type = ClassLoader::APP_LOADER;
ClassLoaderExt::set_has_app_classes();
} else if (SystemDictionary::is_platform_class_loader(loader)) {
classloader_type = ClassLoader::PLATFORM_LOADER;
ClassLoaderExt::set_has_platform_classes();
}
result->set_shared_classpath_index(classpath_index); result->set_shared_classpath_index(classpath_index);
result->set_class_loader_type(classloader_type); result->set_class_loader_type(classloader_type);
} }
@ -82,6 +90,13 @@ public:
return true; return true;
} }
static Klass* load_one_class(ClassListParser* parser, TRAPS); static Klass* load_one_class(ClassListParser* parser, TRAPS);
#if INCLUDE_CDS
static void set_has_app_classes() {}
static void set_has_platform_classes() {}
static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, TRAPS) {
return NULL;
}
#endif
}; };
#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP #endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP

@ -85,6 +85,7 @@ DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass)
void Dictionary::free_entry(DictionaryEntry* entry) { void Dictionary::free_entry(DictionaryEntry* entry) {
// avoid recursion when deleting linked list // avoid recursion when deleting linked list
// pd_set is accessed during a safepoint.
while (entry->pd_set() != NULL) { while (entry->pd_set() != NULL) {
ProtectionDomainEntry* to_delete = entry->pd_set(); ProtectionDomainEntry* to_delete = entry->pd_set();
entry->set_pd_set(to_delete->next()); entry->set_pd_set(to_delete->next());
@ -101,7 +102,7 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
if (protection_domain == instance_klass()->protection_domain()) { if (protection_domain == instance_klass()->protection_domain()) {
// Ensure this doesn't show up in the pd_set (invariant) // Ensure this doesn't show up in the pd_set (invariant)
bool in_pd_set = false; bool in_pd_set = false;
for (ProtectionDomainEntry* current = _pd_set; for (ProtectionDomainEntry* current = pd_set_acquire();
current != NULL; current != NULL;
current = current->next()) { current = current->next()) {
if (current->protection_domain() == protection_domain) { if (current->protection_domain() == protection_domain) {
@ -121,7 +122,7 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
return true; return true;
} }
for (ProtectionDomainEntry* current = _pd_set; for (ProtectionDomainEntry* current = pd_set_acquire();
current != NULL; current != NULL;
current = current->next()) { current = current->next()) {
if (current->protection_domain() == protection_domain) return true; if (current->protection_domain() == protection_domain) return true;
@ -135,12 +136,12 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_
if (!contains_protection_domain(protection_domain())) { if (!contains_protection_domain(protection_domain())) {
ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain); ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain);
ProtectionDomainEntry* new_head = ProtectionDomainEntry* new_head =
new ProtectionDomainEntry(entry, _pd_set); new ProtectionDomainEntry(entry, pd_set());
// Warning: Preserve store ordering. The SystemDictionary is read // Warning: Preserve store ordering. The SystemDictionary is read
// without locks. The new ProtectionDomainEntry must be // without locks. The new ProtectionDomainEntry must be
// complete before other threads can be allowed to see it // complete before other threads can be allowed to see it
// via a store to _pd_set. // via a store to _pd_set.
OrderAccess::release_store_ptr(&_pd_set, new_head); release_set_pd_set(new_head);
} }
LogTarget(Trace, protectiondomain) lt; LogTarget(Trace, protectiondomain) lt;
if (lt.is_enabled()) { if (lt.is_enabled()) {
@ -365,11 +366,21 @@ void Dictionary::reorder_dictionary_for_sharing() {
for (int i = 0; i < table_size(); ++i) { for (int i = 0; i < table_size(); ++i) {
DictionaryEntry* p = bucket(i); DictionaryEntry* p = bucket(i);
while (p != NULL) { while (p != NULL) {
DictionaryEntry* tmp; DictionaryEntry* next = p->next();
tmp = p->next(); InstanceKlass*ik = p->instance_klass();
p->set_next(master_list); // we cannot include signed classes in the archive because the certificates
master_list = p; // used during dump time may be different than those used during
p = tmp; // runtime (due to expiration, etc).
if (ik->signers() != NULL) {
ResourceMark rm;
tty->print_cr("Preload Warning: Skipping %s from signed JAR",
ik->name()->as_C_string());
free_entry(p);
} else {
p->set_next(master_list);
master_list = p;
}
p = next;
} }
set_entry(i, NULL); set_entry(i, NULL);
} }

@ -29,6 +29,7 @@
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/oop.hpp" #include "oops/oop.hpp"
#include "runtime/orderAccess.hpp"
#include "utilities/hashtable.hpp" #include "utilities/hashtable.hpp"
#include "utilities/ostream.hpp" #include "utilities/ostream.hpp"
@ -48,21 +49,6 @@ class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name); DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
protected: protected:
DictionaryEntry* bucket(int i) const {
return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
}
// The following method is not MT-safe and must be done under lock.
DictionaryEntry** bucket_addr(int i) {
return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
}
void add_entry(int index, DictionaryEntry* new_entry) {
Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
}
void free_entry(DictionaryEntry* entry);
static size_t entry_size(); static size_t entry_size();
public: public:
Dictionary(ClassLoaderData* loader_data, int table_size); Dictionary(ClassLoaderData* loader_data, int table_size);
@ -106,6 +92,24 @@ public:
void print_on(outputStream* st) const; void print_on(outputStream* st) const;
void verify(); void verify();
DictionaryEntry* bucket(int i) const {
return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
}
// The following method is not MT-safe and must be done under lock.
DictionaryEntry** bucket_addr(int i) {
return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
}
void add_entry(int index, DictionaryEntry* new_entry) {
Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
}
void unlink_entry(DictionaryEntry* entry) {
Hashtable<InstanceKlass*, mtClass>::unlink_entry((HashtableEntry<InstanceKlass*, mtClass>*)entry);
}
void free_entry(DictionaryEntry* entry);
}; };
// An entry in the class loader data dictionaries, this describes a class as // An entry in the class loader data dictionaries, this describes a class as
@ -134,7 +138,7 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
// It is essentially a cache to avoid repeated Java up-calls to // It is essentially a cache to avoid repeated Java up-calls to
// ClassLoader.checkPackageAccess(). // ClassLoader.checkPackageAccess().
// //
ProtectionDomainEntry* _pd_set; ProtectionDomainEntry* volatile _pd_set;
public: public:
// Tells whether a protection is in the approved set. // Tells whether a protection is in the approved set.
@ -153,8 +157,15 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr(); return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr();
} }
ProtectionDomainEntry* pd_set() const { return _pd_set; } ProtectionDomainEntry* pd_set() const { return _pd_set; }
void set_pd_set(ProtectionDomainEntry* pd_set) { _pd_set = pd_set; } void set_pd_set(ProtectionDomainEntry* new_head) { _pd_set = new_head; }
ProtectionDomainEntry* pd_set_acquire() const {
return (ProtectionDomainEntry*)OrderAccess::load_ptr_acquire(&_pd_set);
}
void release_set_pd_set(ProtectionDomainEntry* new_head) {
OrderAccess::release_store_ptr(&_pd_set, new_head);
}
// Tells whether the initiating class' protection domain can access the klass in this entry // Tells whether the initiating class' protection domain can access the klass in this entry
bool is_valid_protection_domain(Handle protection_domain) { bool is_valid_protection_domain(Handle protection_domain) {
@ -167,7 +178,7 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
} }
void verify_protection_domain_set() { void verify_protection_domain_set() {
for (ProtectionDomainEntry* current = _pd_set; for (ProtectionDomainEntry* current = pd_set(); // accessed at a safepoint
current != NULL; current != NULL;
current = current->_next) { current = current->_next) {
current->_pd_cache->protection_domain()->verify(); current->_pd_cache->protection_domain()->verify();
@ -181,7 +192,7 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
void print_count(outputStream *st) { void print_count(outputStream *st) {
int count = 0; int count = 0;
for (ProtectionDomainEntry* current = _pd_set; for (ProtectionDomainEntry* current = pd_set(); // accessed inside SD lock
current != NULL; current != NULL;
current = current->_next) { current = current->_next) {
count++; count++;
@ -246,10 +257,6 @@ class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> { class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> {
friend class VMStructs; friend class VMStructs;
private: private:
SymbolPropertyEntry* bucket(int i) {
return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
}
// The following method is not MT-safe and must be done under lock. // The following method is not MT-safe and must be done under lock.
SymbolPropertyEntry** bucket_addr(int i) { SymbolPropertyEntry** bucket_addr(int i) {
return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i); return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i);
@ -303,5 +310,9 @@ public:
void methods_do(void f(Method*)); void methods_do(void f(Method*));
void verify(); void verify();
SymbolPropertyEntry* bucket(int i) {
return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
}
}; };
#endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP #endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP

@ -70,11 +70,25 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
ClassLoaderData* loader_data = ClassLoaderData* loader_data =
ClassLoaderData::class_loader_data(class_loader()); ClassLoaderData::class_loader_data(class_loader());
int path_index = ik->shared_classpath_index(); int path_index = ik->shared_classpath_index();
SharedClassPathEntry* ent = const char* pathname;
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); if (path_index < 0) {
// shared classes loaded by user defined class loader
// do not have shared_classpath_index
ModuleEntry* mod_entry = ik->module();
if (mod_entry != NULL && (mod_entry->location() != NULL)) {
ResourceMark rm;
pathname = (const char*)(mod_entry->location()->as_C_string());
} else {
pathname = "";
}
} else {
SharedClassPathEntry* ent =
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
pathname = ent == NULL ? NULL : ent->name();
}
ClassFileStream* stream = new ClassFileStream(ptr, ClassFileStream* stream = new ClassFileStream(ptr,
end_ptr - ptr, end_ptr - ptr,
ent == NULL ? NULL : ent->name(), pathname,
ClassFileStream::verify); ClassFileStream::verify);
ClassFileParser parser(stream, ClassFileParser parser(stream,
class_name, class_name,
@ -215,8 +229,10 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
TRACE_KLASS_CREATION(result, parser, THREAD); TRACE_KLASS_CREATION(result, parser, THREAD);
#if INCLUDE_CDS && INCLUDE_JVMTI #if INCLUDE_CDS
if (DumpSharedSpaces) { if (DumpSharedSpaces) {
ClassLoader::record_shared_class_loader_type(result, stream);
#if INCLUDE_JVMTI
assert(cached_class_file == NULL, "Sanity"); assert(cached_class_file == NULL, "Sanity");
// Archive the class stream data into the optional data section // Archive the class stream data into the optional data section
JvmtiCachedClassFileData *p; JvmtiCachedClassFileData *p;
@ -233,8 +249,9 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
p->length = len; p->length = len;
memcpy(p->data, bytes, len); memcpy(p->data, bytes, len);
result->set_archived_class_data(p); result->set_archived_class_data(p);
#endif // INCLUDE_JVMTI
} }
#endif #endif // INCLUDE_CDS
return result; return result;
} }

@ -729,7 +729,6 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
} }
G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity()); G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
assert(string_space->length() <= 2, "sanity");
return true; return true;
} }

@ -66,6 +66,7 @@
#include "prims/resolvedMethodTable.hpp" #include "prims/resolvedMethodTable.hpp"
#include "prims/methodHandles.hpp" #include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/arguments_ext.hpp"
#include "runtime/biasedLocking.hpp" #include "runtime/biasedLocking.hpp"
#include "runtime/fieldType.hpp" #include "runtime/fieldType.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
@ -869,7 +870,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// during compilations. // during compilations.
MutexLocker mu(Compile_lock, THREAD); MutexLocker mu(Compile_lock, THREAD);
update_dictionary(d_index, d_hash, p_index, p_hash, update_dictionary(d_index, d_hash, p_index, p_hash,
k, class_loader, THREAD); k, class_loader, THREAD);
} }
if (JvmtiExport::should_post_class_load()) { if (JvmtiExport::should_post_class_load()) {
@ -910,12 +911,9 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
if (protection_domain() == NULL) return k; if (protection_domain() == NULL) return k;
// Check the protection domain has the right access // Check the protection domain has the right access
{ if (dictionary->is_valid_protection_domain(d_index, d_hash, name,
MutexLocker mu(SystemDictionary_lock, THREAD); protection_domain)) {
if (dictionary->is_valid_protection_domain(d_index, d_hash, name, return k;
protection_domain)) {
return k;
}
} }
// Verify protection domain. If it fails an exception is thrown // Verify protection domain. If it fails an exception is thrown
@ -1009,7 +1007,6 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
// Create a new CLD for anonymous class, that uses the same class loader // Create a new CLD for anonymous class, that uses the same class loader
// as the host_klass // as the host_klass
guarantee(host_klass->class_loader() == class_loader(), "should be the same"); guarantee(host_klass->class_loader() == class_loader(), "should be the same");
guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL); loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
} else { } else {
loader_data = ClassLoaderData::class_loader_data(class_loader()); loader_data = ClassLoaderData::class_loader_data(class_loader());
@ -1078,6 +1075,15 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
Handle protection_domain, Handle protection_domain,
ClassFileStream* st, ClassFileStream* st,
TRAPS) { TRAPS) {
#if INCLUDE_CDS
ResourceMark rm(THREAD);
if (DumpSharedSpaces && !class_loader.is_null() &&
!ArgumentsExt::using_AppCDS() && strcmp(class_name->as_C_string(), "Unnamed") != 0) {
// If AppCDS is not enabled, don't define the class at dump time (except for the "Unnamed"
// class, which is used by MethodHandles).
THROW_MSG_NULL(vmSymbols::java_lang_ClassNotFoundException(), class_name->as_C_string());
}
#endif
HandleMark hm(THREAD); HandleMark hm(THREAD);
@ -1104,11 +1110,13 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
InstanceKlass* k = NULL; InstanceKlass* k = NULL;
#if INCLUDE_CDS #if INCLUDE_CDS
k = SystemDictionaryShared::lookup_from_stream(class_name, if (!DumpSharedSpaces) {
class_loader, k = SystemDictionaryShared::lookup_from_stream(class_name,
protection_domain, class_loader,
st, protection_domain,
CHECK_NULL); st,
CHECK_NULL);
}
#endif #endif
if (k == NULL) { if (k == NULL) {
@ -1217,6 +1225,16 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
"Cannot use sharing if java.base is patched"); "Cannot use sharing if java.base is patched");
ResourceMark rm; ResourceMark rm;
int path_index = ik->shared_classpath_index(); int path_index = ik->shared_classpath_index();
ClassLoaderData* loader_data = class_loader_data(class_loader);
if (path_index < 0) {
// path_index < 0 indicates that the class is intended for a custom loader
// and should not be loaded by boot/platform/app loaders
if (loader_data->is_builtin_class_loader_data()) {
return false;
} else {
return true;
}
}
SharedClassPathEntry* ent = SharedClassPathEntry* ent =
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
if (!Universe::is_module_initialized()) { if (!Universe::is_module_initialized()) {
@ -1230,7 +1248,6 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
PackageEntry* pkg_entry = NULL; PackageEntry* pkg_entry = NULL;
ModuleEntry* mod_entry = NULL; ModuleEntry* mod_entry = NULL;
const char* pkg_string = NULL; const char* pkg_string = NULL;
ClassLoaderData* loader_data = class_loader_data(class_loader);
pkg_name = InstanceKlass::package_from_name(class_name, CHECK_false); pkg_name = InstanceKlass::package_from_name(class_name, CHECK_false);
if (pkg_name != NULL) { if (pkg_name != NULL) {
pkg_string = pkg_name->as_C_string(); pkg_string = pkg_name->as_C_string();
@ -1403,6 +1420,18 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
} }
return ik; return ik;
} }
void SystemDictionary::clear_invoke_method_table() {
SymbolPropertyEntry* spe = NULL;
for (int index = 0; index < _invoke_method_table->table_size(); index++) {
SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
while (p != NULL) {
spe = p;
p = p->next();
_invoke_method_table->free_entry(spe);
}
}
}
#endif // INCLUDE_CDS #endif // INCLUDE_CDS
InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
@ -1449,7 +1478,6 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle
} }
} }
} else { } else {
assert(!DumpSharedSpaces, "Archive dumped after module system initialization");
// After the module system has been initialized, check if the class' // After the module system has been initialized, check if the class'
// package is in a module defined to the boot loader. // package is in a module defined to the boot loader.
if (pkg_name == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) { if (pkg_name == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
@ -1968,8 +1996,19 @@ void SystemDictionary::methods_do(void f(Method*)) {
invoke_method_table()->methods_do(f); invoke_method_table()->methods_do(f);
} }
class RemoveClassesClosure : public CLDClosure {
public:
void do_cld(ClassLoaderData* cld) {
if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
cld->dictionary()->remove_classes_in_error_state();
}
}
};
void SystemDictionary::remove_classes_in_error_state() { void SystemDictionary::remove_classes_in_error_state() {
ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state(); ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
RemoveClassesClosure rcc;
ClassLoaderDataGraph::cld_do(&rcc);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -2910,6 +2949,56 @@ int SystemDictionaryDCmd::num_arguments() {
} }
} }
class CombineDictionariesClosure : public CLDClosure {
private:
Dictionary* _master_dictionary;
public:
CombineDictionariesClosure(Dictionary* master_dictionary) :
_master_dictionary(master_dictionary) {}
void do_cld(ClassLoaderData* cld) {
ResourceMark rm;
if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
Dictionary* curr_dictionary = cld->dictionary();
DictionaryEntry* p = curr_dictionary->bucket(i);
while (p != NULL) {
Symbol* name = p->instance_klass()->name();
unsigned int d_hash = _master_dictionary->compute_hash(name);
int d_index = _master_dictionary->hash_to_index(d_hash);
DictionaryEntry* next = p->next();
if (p->literal()->class_loader_data() != cld) {
// This is an initiating class loader entry; don't use it
log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
curr_dictionary->free_entry(p);
} else {
log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
curr_dictionary->unlink_entry(p);
p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
_master_dictionary->add_entry(d_index, p);
}
p = next;
}
*curr_dictionary->bucket_addr(i) = NULL;
}
}
}
};
// Combining platform and system loader dictionaries into boot loader dictionaries.
// During run time, we only have one shared dictionary.
void SystemDictionary::combine_shared_dictionaries() {
assert(DumpSharedSpaces, "dump time only");
Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
CombineDictionariesClosure cdc(master_dictionary);
ClassLoaderDataGraph::cld_do(&cdc);
// These tables are no longer valid or necessary. Keeping them around will
// cause SystemDictionary::verify() to fail. Let's empty them.
_placeholders = new PlaceholderTable(_placeholder_table_size);
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
NOT_PRODUCT(SystemDictionary::verify());
}
// caller needs ResourceMark // caller needs ResourceMark
const char* SystemDictionary::loader_name(const oop loader) { const char* SystemDictionary::loader_name(const oop loader) {

@ -385,6 +385,7 @@ public:
public: public:
// Sharing support. // Sharing support.
static void reorder_dictionary_for_sharing(); static void reorder_dictionary_for_sharing();
static void combine_shared_dictionaries();
static size_t count_bytes_for_buckets(); static size_t count_bytes_for_buckets();
static size_t count_bytes_for_table(); static size_t count_bytes_for_table();
static void copy_buckets(char* top, char* end); static void copy_buckets(char* top, char* end);
@ -643,6 +644,7 @@ public:
TRAPS); TRAPS);
static bool is_system_class_loader(oop class_loader); static bool is_system_class_loader(oop class_loader);
static bool is_platform_class_loader(oop class_loader); static bool is_platform_class_loader(oop class_loader);
static void clear_invoke_method_table();
protected: protected:
static InstanceKlass* find_shared_class(Symbol* class_name); static InstanceKlass* find_shared_class(Symbol* class_name);

@ -1220,7 +1220,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
// for stack scanning. // for stack scanning.
if (state == not_entrant) { if (state == not_entrant) {
mark_as_seen_on_stack(); mark_as_seen_on_stack();
OrderAccess::storestore(); OrderAccess::storestore(); // _stack_traversal_mark and _state
} }
// Change state // Change state

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -136,7 +136,7 @@ class nmethod : public CompiledMethod {
// stack. An not_entrant method can be removed when there are no // stack. An not_entrant method can be removed when there are no
// more activations, i.e., when the _stack_traversal_mark is less than // more activations, i.e., when the _stack_traversal_mark is less than
// current sweep traversal index. // current sweep traversal index.
volatile jlong _stack_traversal_mark; volatile long _stack_traversal_mark;
// The _hotness_counter indicates the hotness of a method. The higher // The _hotness_counter indicates the hotness of a method. The higher
// the value the hotter the method. The hotness counter of a nmethod is // the value the hotter the method. The hotness counter of a nmethod is
@ -396,8 +396,8 @@ public:
public: public:
// Sweeper support // Sweeper support
jlong stack_traversal_mark() { return OrderAccess::load_acquire(&_stack_traversal_mark); } long stack_traversal_mark() { return _stack_traversal_mark; }
void set_stack_traversal_mark(jlong l) { OrderAccess::release_store(&_stack_traversal_mark, l); } void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; }
// implicit exceptions support // implicit exceptions support
address continuation_for_implicit_exception(address pc); address continuation_for_implicit_exception(address pc);

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,7 +30,6 @@
#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "runtime/stubCodeGenerator.hpp" #include "runtime/stubCodeGenerator.hpp"
@ -163,7 +162,6 @@ class decode_env {
bool _print_pc; bool _print_pc;
bool _print_bytes; bool _print_bytes;
address _cur_insn; address _cur_insn;
int _total_ticks;
int _bytes_per_line; // arch-specific formatting option int _bytes_per_line; // arch-specific formatting option
static bool match(const char* event, const char* tag) { static bool match(const char* event, const char* tag) {
@ -213,18 +211,6 @@ class decode_env {
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
// this calls reloc_string_for which calls oop::print_value_on // this calls reloc_string_for which calls oop::print_value_on
} }
// Output pc bucket ticks if we have any
if (total_ticks() != 0) {
address bucket_pc = FlatProfiler::bucket_start_for(pc);
if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
int bucket_count = FlatProfiler::bucket_count_for(pc0);
if (bucket_count != 0) {
st->bol();
st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
}
}
}
// follow each complete insn by a nice newline // follow each complete insn by a nice newline
st->cr(); st->cr();
} }
@ -233,8 +219,6 @@ class decode_env {
outputStream* output() { return _output; } outputStream* output() { return _output; }
address cur_insn() { return _cur_insn; } address cur_insn() { return _cur_insn; }
int total_ticks() { return _total_ticks; }
void set_total_ticks(int n) { _total_ticks = n; }
const char* options() { return _option_buf; } const char* options() { return _option_buf; }
}; };
@ -561,20 +545,6 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
#endif #endif
env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p))); env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p)));
// If there has been profiling, print the buckets.
if (FlatProfiler::bucket_start_for(p) != NULL) {
unsigned char* p1 = p;
int total_bucket_count = 0;
while (p1 < end) {
unsigned char* p0 = p1;
p1 += pd_instruction_alignment();
address bucket_pc = FlatProfiler::bucket_start_for(p1);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
total_bucket_count += FlatProfiler::bucket_count_for(p0);
}
env.set_total_ticks(total_bucket_count);
}
// Print constant table. // Print constant table.
if (nm->consts_size() > 0) { if (nm->consts_size() > 0) {
nm->print_nmethod_labels(env.output(), nm->consts_begin()); nm->print_nmethod_labels(env.output(), nm->consts_begin());

@ -1719,7 +1719,6 @@ jint G1CollectedHeap::initialize() {
G1BlockOffsetTable::compute_size(g1_rs.size() / HeapWordSize), G1BlockOffsetTable::compute_size(g1_rs.size() / HeapWordSize),
G1BlockOffsetTable::heap_map_factor()); G1BlockOffsetTable::heap_map_factor());
ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize));
G1RegionToSpaceMapper* cardtable_storage = G1RegionToSpaceMapper* cardtable_storage =
create_aux_memory_mapper("Card Table", create_aux_memory_mapper("Card Table",
G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize), G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize),

@ -54,7 +54,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
_gc_par_phases[UniverseRoots] = new WorkerDataArray<double>(max_gc_threads, "Universe Roots (ms):"); _gc_par_phases[UniverseRoots] = new WorkerDataArray<double>(max_gc_threads, "Universe Roots (ms):");
_gc_par_phases[JNIRoots] = new WorkerDataArray<double>(max_gc_threads, "JNI Handles Roots (ms):"); _gc_par_phases[JNIRoots] = new WorkerDataArray<double>(max_gc_threads, "JNI Handles Roots (ms):");
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>(max_gc_threads, "ObjectSynchronizer Roots (ms):"); _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>(max_gc_threads, "ObjectSynchronizer Roots (ms):");
_gc_par_phases[FlatProfilerRoots] = new WorkerDataArray<double>(max_gc_threads, "FlatProfiler Roots (ms):");
_gc_par_phases[ManagementRoots] = new WorkerDataArray<double>(max_gc_threads, "Management Roots (ms):"); _gc_par_phases[ManagementRoots] = new WorkerDataArray<double>(max_gc_threads, "Management Roots (ms):");
_gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>(max_gc_threads, "SystemDictionary Roots (ms):"); _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>(max_gc_threads, "SystemDictionary Roots (ms):");
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>(max_gc_threads, "CLDG Roots (ms):"); _gc_par_phases[CLDGRoots] = new WorkerDataArray<double>(max_gc_threads, "CLDG Roots (ms):");

@ -49,7 +49,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
UniverseRoots, UniverseRoots,
JNIRoots, JNIRoots,
ObjectSynchronizerRoots, ObjectSynchronizerRoots,
FlatProfilerRoots,
ManagementRoots, ManagementRoots,
SystemDictionaryRoots, SystemDictionaryRoots,
CLDGRoots, CLDGRoots,

@ -62,7 +62,7 @@ public:
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _vo)) { if (_g1h->is_obj_dead_cond(obj, _vo)) {
Log(gc, verify) log; Log(gc, verify) log;
log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj)); log.error("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
if (_vo == VerifyOption_G1UseMarkWord) { if (_vo == VerifyOption_G1UseMarkWord) {
log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark())); log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
} }

@ -48,7 +48,6 @@
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp" #include "runtime/biasedLocking.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/synchronizer.hpp" #include "runtime/synchronizer.hpp"
#include "runtime/thread.hpp" #include "runtime/thread.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,6 @@
#include "gc/g1/g1RootProcessor.hpp" #include "gc/g1/g1RootProcessor.hpp"
#include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegion.inline.hpp"
#include "memory/allocation.inline.hpp" #include "memory/allocation.inline.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/mutex.hpp" #include "runtime/mutex.hpp"
#include "services/management.hpp" #include "services/management.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
@ -271,13 +270,6 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
} }
} }
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i);
if (!_process_strong_tasks.is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
FlatProfiler::oops_do(strong_roots);
}
}
{ {
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i); G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i);
if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) { if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) {

@ -57,7 +57,6 @@ class G1RootProcessor : public StackObj {
G1RP_PS_Universe_oops_do, G1RP_PS_Universe_oops_do,
G1RP_PS_JNIHandles_oops_do, G1RP_PS_JNIHandles_oops_do,
G1RP_PS_ObjectSynchronizer_oops_do, G1RP_PS_ObjectSynchronizer_oops_do,
G1RP_PS_FlatProfiler_oops_do,
G1RP_PS_Management_oops_do, G1RP_PS_Management_oops_do,
G1RP_PS_SystemDictionary_oops_do, G1RP_PS_SystemDictionary_oops_do,
G1RP_PS_ClassLoaderDataGraph_oops_do, G1RP_PS_ClassLoaderDataGraph_oops_do,

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,6 @@
#include "oops/objArrayKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/jniHandles.hpp" #include "runtime/jniHandles.hpp"
#include "runtime/thread.hpp" #include "runtime/thread.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
@ -105,10 +104,6 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
ObjectSynchronizer::oops_do(&mark_and_push_closure); ObjectSynchronizer::oops_do(&mark_and_push_closure);
break; break;
case flat_profiler:
FlatProfiler::oops_do(&mark_and_push_closure);
break;
case management: case management:
Management::oops_do(&mark_and_push_closure); Management::oops_do(&mark_and_push_closure);
break; break;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -94,12 +94,11 @@ class MarkFromRootsTask : public GCTask {
jni_handles = 2, jni_handles = 2,
threads = 3, threads = 3,
object_synchronizer = 4, object_synchronizer = 4,
flat_profiler = 5, management = 5,
management = 6, jvmti = 6,
jvmti = 7, system_dictionary = 7,
system_dictionary = 8, class_loader_data = 8,
class_loader_data = 9, code_cache = 9
code_cache = 10
}; };
private: private:
RootType _root_type; RootType _root_type;

@ -50,7 +50,6 @@
#include "logging/log.hpp" #include "logging/log.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp" #include "runtime/biasedLocking.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/safepoint.hpp" #include "runtime/safepoint.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "services/management.hpp" #include "services/management.hpp"
@ -514,7 +513,6 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
MarkingCodeBlobClosure each_active_code_blob(mark_and_push_closure(), !CodeBlobToOopClosure::FixRelocations); MarkingCodeBlobClosure each_active_code_blob(mark_and_push_closure(), !CodeBlobToOopClosure::FixRelocations);
Threads::oops_do(mark_and_push_closure(), &each_active_code_blob); Threads::oops_do(mark_and_push_closure(), &each_active_code_blob);
ObjectSynchronizer::oops_do(mark_and_push_closure()); ObjectSynchronizer::oops_do(mark_and_push_closure());
FlatProfiler::oops_do(mark_and_push_closure());
Management::oops_do(mark_and_push_closure()); Management::oops_do(mark_and_push_closure());
JvmtiExport::oops_do(mark_and_push_closure()); JvmtiExport::oops_do(mark_and_push_closure());
SystemDictionary::always_strong_oops_do(mark_and_push_closure()); SystemDictionary::always_strong_oops_do(mark_and_push_closure());
@ -607,7 +605,6 @@ void PSMarkSweep::mark_sweep_phase3() {
JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles
Threads::oops_do(adjust_pointer_closure(), NULL); Threads::oops_do(adjust_pointer_closure(), NULL);
ObjectSynchronizer::oops_do(adjust_pointer_closure()); ObjectSynchronizer::oops_do(adjust_pointer_closure());
FlatProfiler::oops_do(adjust_pointer_closure());
Management::oops_do(adjust_pointer_closure()); Management::oops_do(adjust_pointer_closure());
JvmtiExport::oops_do(adjust_pointer_closure()); JvmtiExport::oops_do(adjust_pointer_closure());
SystemDictionary::oops_do(adjust_pointer_closure()); SystemDictionary::oops_do(adjust_pointer_closure());

@ -60,7 +60,6 @@
#include "oops/objArrayKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/safepoint.hpp" #include "runtime/safepoint.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "services/management.hpp" #include "services/management.hpp"
@ -2086,7 +2085,6 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
// We scan the thread roots in parallel // We scan the thread roots in parallel
Threads::create_thread_roots_marking_tasks(q); Threads::create_thread_roots_marking_tasks(q);
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::object_synchronizer)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::object_synchronizer));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::flat_profiler));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::management)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::management));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data));
@ -2169,7 +2167,6 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
JNIHandles::oops_do(&oop_closure); // Global (strong) JNI handles JNIHandles::oops_do(&oop_closure); // Global (strong) JNI handles
Threads::oops_do(&oop_closure, NULL); Threads::oops_do(&oop_closure, NULL);
ObjectSynchronizer::oops_do(&oop_closure); ObjectSynchronizer::oops_do(&oop_closure);
FlatProfiler::oops_do(&oop_closure);
Management::oops_do(&oop_closure); Management::oops_do(&oop_closure);
JvmtiExport::oops_do(&oop_closure); JvmtiExport::oops_do(&oop_closure);
SystemDictionary::oops_do(&oop_closure); SystemDictionary::oops_do(&oop_closure);

@ -49,7 +49,6 @@
#include "logging/log.hpp" #include "logging/log.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp" #include "runtime/biasedLocking.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/threadCritical.hpp" #include "runtime/threadCritical.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
@ -381,7 +380,6 @@ bool PSScavenge::invoke_no_policy() {
// We scan the thread roots in parallel // We scan the thread roots in parallel
Threads::create_thread_roots_tasks(q); Threads::create_thread_roots_tasks(q);
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::object_synchronizer)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::object_synchronizer));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::flat_profiler));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data));

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,6 @@
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/thread.hpp" #include "runtime/thread.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "services/management.hpp" #include "services/management.hpp"
@ -74,10 +73,6 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) {
ObjectSynchronizer::oops_do(&roots_closure); ObjectSynchronizer::oops_do(&roots_closure);
break; break;
case flat_profiler:
FlatProfiler::oops_do(&roots_closure);
break;
case system_dictionary: case system_dictionary:
SystemDictionary::oops_do(&roots_closure); SystemDictionary::oops_do(&roots_closure);
break; break;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -57,12 +57,11 @@ class ScavengeRootsTask : public GCTask {
jni_handles = 2, jni_handles = 2,
threads = 3, threads = 3,
object_synchronizer = 4, object_synchronizer = 4,
flat_profiler = 5, system_dictionary = 5,
system_dictionary = 6, class_loader_data = 6,
class_loader_data = 7, management = 7,
management = 8, jvmti = 8,
jvmti = 9, code_cache = 9
code_cache = 10
}; };
private: private:
RootType _root_type; RootType _root_type;

@ -46,7 +46,6 @@
#include "oops/instanceRefKlass.hpp" #include "oops/instanceRefKlass.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/synchronizer.hpp" #include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"

@ -47,7 +47,6 @@
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp" #include "runtime/biasedLocking.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.hpp" #include "runtime/handles.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/java.hpp" #include "runtime/java.hpp"
@ -71,7 +70,6 @@ enum GCH_strong_roots_tasks {
GCH_PS_Universe_oops_do, GCH_PS_Universe_oops_do,
GCH_PS_JNIHandles_oops_do, GCH_PS_JNIHandles_oops_do,
GCH_PS_ObjectSynchronizer_oops_do, GCH_PS_ObjectSynchronizer_oops_do,
GCH_PS_FlatProfiler_oops_do,
GCH_PS_Management_oops_do, GCH_PS_Management_oops_do,
GCH_PS_SystemDictionary_oops_do, GCH_PS_SystemDictionary_oops_do,
GCH_PS_ClassLoaderDataGraph_oops_do, GCH_PS_ClassLoaderDataGraph_oops_do,
@ -606,9 +604,6 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
if (!_process_strong_tasks->is_task_claimed(GCH_PS_ObjectSynchronizer_oops_do)) { if (!_process_strong_tasks->is_task_claimed(GCH_PS_ObjectSynchronizer_oops_do)) {
ObjectSynchronizer::oops_do(strong_roots); ObjectSynchronizer::oops_do(strong_roots);
} }
if (!_process_strong_tasks->is_task_claimed(GCH_PS_FlatProfiler_oops_do)) {
FlatProfiler::oops_do(strong_roots);
}
if (!_process_strong_tasks->is_task_claimed(GCH_PS_Management_oops_do)) { if (!_process_strong_tasks->is_task_claimed(GCH_PS_Management_oops_do)) {
Management::oops_do(strong_roots); Management::oops_do(strong_roots);
} }

@ -109,6 +109,11 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
MetadataFactory::free_metadata(loader_data, cache); MetadataFactory::free_metadata(loader_data, cache);
_pool->set_cache(NULL); // so the verifier isn't confused _pool->set_cache(NULL); // so the verifier isn't confused
} }
DEBUG_ONLY(
if (DumpSharedSpaces) {
cache->verify_just_initialized();
})
} }

@ -140,6 +140,7 @@
LOG_TAG(timer) \ LOG_TAG(timer) \
LOG_TAG(update) \ LOG_TAG(update) \
LOG_TAG(unload) /* Trace unloading of classes */ \ LOG_TAG(unload) /* Trace unloading of classes */ \
LOG_TAG(unshareable) \
LOG_TAG(verification) \ LOG_TAG(verification) \
LOG_TAG(verify) \ LOG_TAG(verify) \
LOG_TAG(vmoperation) \ LOG_TAG(vmoperation) \

@ -275,7 +275,8 @@ private:
address, bool, address, bool,
UniqueMetaspaceClosure::my_hash, // solaris compiler doesn't like: primitive_hash<address> UniqueMetaspaceClosure::my_hash, // solaris compiler doesn't like: primitive_hash<address>
UniqueMetaspaceClosure::my_equals, // solaris compiler doesn't like: primitive_equals<address> UniqueMetaspaceClosure::my_equals, // solaris compiler doesn't like: primitive_equals<address>
16384> _has_been_visited; 15889, // prime number
ResourceObj::C_HEAP> _has_been_visited;
}; };
#endif // SHARE_VM_MEMORY_METASPACE_ITERATOR_HPP #endif // SHARE_VM_MEMORY_METASPACE_ITERATOR_HPP

@ -374,25 +374,63 @@ address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) {
// Global object for holding classes that have been loaded. Since this // Global object for holding classes that have been loaded. Since this
// is run at a safepoint just before exit, this is the entire set of classes. // is run at a safepoint just before exit, this is the entire set of classes.
static GrowableArray<Klass*>* _global_klass_objects; static GrowableArray<Klass*>* _global_klass_objects;
static void collect_array_classes(Klass* k) {
_global_klass_objects->append_if_missing(k);
if (k->is_array_klass()) {
// Add in the array classes too
ArrayKlass* ak = ArrayKlass::cast(k);
Klass* h = ak->higher_dimension();
if (h != NULL) {
h->array_klasses_do(collect_array_classes);
}
}
}
class CollectClassesClosure : public KlassClosure { class CollectClassesClosure : public KlassClosure {
void do_klass(Klass* k) { void do_klass(Klass* k) {
if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) { if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
_global_klass_objects->append_if_missing(k); _global_klass_objects->append_if_missing(k);
} }
if (k->is_array_klass()) {
// Add in the array classes too
ArrayKlass* ak = ArrayKlass::cast(k);
Klass* h = ak->higher_dimension();
if (h != NULL) {
h->array_klasses_do(collect_array_classes);
}
}
} }
}; };
static void remove_unshareable_in_classes() { static void remove_unshareable_in_classes() {
for (int i = 0; i < _global_klass_objects->length(); i++) { for (int i = 0; i < _global_klass_objects->length(); i++) {
Klass* k = _global_klass_objects->at(i); Klass* k = _global_klass_objects->at(i);
k->remove_unshareable_info(); if (!k->is_objArray_klass()) {
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
// on their array classes.
assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be");
k->remove_unshareable_info();
}
}
}
static void remove_java_mirror_in_classes() {
for (int i = 0; i < _global_klass_objects->length(); i++) {
Klass* k = _global_klass_objects->at(i);
if (!k->is_objArray_klass()) {
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
// on their array classes.
assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be");
k->remove_java_mirror();
}
} }
} }
static void rewrite_nofast_bytecode(Method* method) { static void rewrite_nofast_bytecode(Method* method) {
RawBytecodeStream bcs(method); BytecodeStream bcs(method);
while (!bcs.is_last_bytecode()) { while (!bcs.is_last_bytecode()) {
Bytecodes::Code opcode = bcs.raw_next(); Bytecodes::Code opcode = bcs.next();
switch (opcode) { switch (opcode) {
case Bytecodes::_getfield: *bcs.bcp() = Bytecodes::_nofast_getfield; break; case Bytecodes::_getfield: *bcs.bcp() = Bytecodes::_nofast_getfield; break;
case Bytecodes::_putfield: *bcs.bcp() = Bytecodes::_nofast_putfield; break; case Bytecodes::_putfield: *bcs.bcp() = Bytecodes::_nofast_putfield; break;
@ -446,6 +484,17 @@ static void relocate_cached_class_file() {
} }
} }
NOT_PRODUCT(
static void assert_not_anonymous_class(InstanceKlass* k) {
assert(!(k->is_anonymous()), "cannot archive anonymous classes");
}
// Anonymous classes are not stored inside any dictionaries. They are created by
// SystemDictionary::parse_stream() with a non-null host_klass.
static void assert_no_anonymoys_classes_in_dictionaries() {
ClassLoaderDataGraph::dictionary_classes_do(assert_not_anonymous_class);
})
// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables. // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
// (In GCC this is the field <Type>::_vptr, i.e., first word in the object.) // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
// //
@ -957,8 +1006,8 @@ public:
} }
memcpy(p, obj, bytes); memcpy(p, obj, bytes);
bool isnew = _new_loc_table->put(obj, (address)p); bool isnew = _new_loc_table->put(obj, (address)p);
assert(isnew, "must be");
log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes); log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
assert(isnew, "must be");
_alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only); _alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
if (ref->msotype() == MetaspaceObj::SymbolType) { if (ref->msotype() == MetaspaceObj::SymbolType) {
@ -1151,6 +1200,9 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
// Reorder the system dictionary. Moving the symbols affects // Reorder the system dictionary. Moving the symbols affects
// how the hash table indices are calculated. // how the hash table indices are calculated.
SystemDictionary::reorder_dictionary_for_sharing(); SystemDictionary::reorder_dictionary_for_sharing();
tty->print("Removing java_mirror ... ");
remove_java_mirror_in_classes();
tty->print_cr("done. ");
NOT_PRODUCT(SystemDictionary::verify();) NOT_PRODUCT(SystemDictionary::verify();)
size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets(); size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets();
@ -1218,11 +1270,20 @@ void VM_PopulateDumpSharedSpace::doit() {
rewrite_nofast_bytecodes_and_calculate_fingerprints(); rewrite_nofast_bytecodes_and_calculate_fingerprints();
tty->print_cr("done. "); tty->print_cr("done. ");
// Move classes from platform/system dictionaries into the boot dictionary
SystemDictionary::combine_shared_dictionaries();
// Remove all references outside the metadata // Remove all references outside the metadata
tty->print("Removing unshareable information ... "); tty->print("Removing unshareable information ... ");
remove_unshareable_in_classes(); remove_unshareable_in_classes();
tty->print_cr("done. "); tty->print_cr("done. ");
// We don't support archiving anonymous classes. Verify that they are not stored in
// the any dictionaries.
NOT_PRODUCT(assert_no_anonymoys_classes_in_dictionaries());
SystemDictionaryShared::finalize_verification_constraints();
ArchiveCompactor::initialize(); ArchiveCompactor::initialize();
ArchiveCompactor::copy_and_compact(); ArchiveCompactor::copy_and_compact();
@ -1312,6 +1373,14 @@ void VM_PopulateDumpSharedSpace::doit() {
ArchiveCompactor::alloc_stats()->print_stats(int(_ro_region.used()), int(_rw_region.used()), ArchiveCompactor::alloc_stats()->print_stats(int(_ro_region.used()), int(_rw_region.used()),
int(_mc_region.used()), int(_md_region.used())); int(_mc_region.used()), int(_md_region.used()));
} }
if (PrintSystemDictionaryAtExit) {
SystemDictionary::print();
}
// There may be other pending VM operations that operate on the InstanceKlasses,
// which will fail because InstanceKlasses::remove_unshareable_info()
// has been called. Forget these operations and exit the VM directly.
vm_direct_exit(0);
} }
void VM_PopulateDumpSharedSpace::print_region_stats() { void VM_PopulateDumpSharedSpace::print_region_stats() {
@ -1438,10 +1507,6 @@ void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
exit(1); exit(1);
} }
} }
// Copy the verification constraints from C_HEAP-alloced GrowableArrays to RO-alloced
// Arrays
SystemDictionaryShared::finalize_verification_constraints();
} }
void MetaspaceShared::prepare_for_dumping() { void MetaspaceShared::prepare_for_dumping() {
@ -1509,17 +1574,11 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
link_and_cleanup_shared_classes(CATCH); link_and_cleanup_shared_classes(CATCH);
tty->print_cr("Rewriting and linking classes: done"); tty->print_cr("Rewriting and linking classes: done");
SystemDictionary::clear_invoke_method_table();
VM_PopulateDumpSharedSpace op; VM_PopulateDumpSharedSpace op;
VMThread::execute(&op); VMThread::execute(&op);
} }
if (PrintSystemDictionaryAtExit) {
SystemDictionary::print();
}
// Since various initialization steps have been undone by this process,
// it is not reasonable to continue running a java process.
exit(0);
} }
@ -1529,8 +1588,14 @@ int MetaspaceShared::preload_classes(const char* class_list_path, TRAPS) {
while (parser.parse_one_line()) { while (parser.parse_one_line()) {
Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD); Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; if (klass == NULL &&
(PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
// print a warning only when the pending exception is class not found
tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
}
CLEAR_PENDING_EXCEPTION;
}
if (klass != NULL) { if (klass != NULL) {
if (log_is_enabled(Trace, cds)) { if (log_is_enabled(Trace, cds)) {
ResourceMark rm; ResourceMark rm;

@ -63,7 +63,6 @@
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/commandLineFlagConstraintList.hpp" #include "runtime/commandLineFlagConstraintList.hpp"
#include "runtime/deoptimization.hpp" #include "runtime/deoptimization.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/init.hpp" #include "runtime/init.hpp"
#include "runtime/java.hpp" #include "runtime/java.hpp"

@ -187,12 +187,29 @@ void ArrayKlass::metaspace_pointers_do(MetaspaceClosure* it) {
void ArrayKlass::remove_unshareable_info() { void ArrayKlass::remove_unshareable_info() {
Klass::remove_unshareable_info(); Klass::remove_unshareable_info();
if (_higher_dimension != NULL) {
ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
ak->remove_unshareable_info();
}
}
void ArrayKlass::remove_java_mirror() {
Klass::remove_java_mirror();
if (_higher_dimension != NULL) {
ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
ak->remove_java_mirror();
}
} }
void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader"); assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader");
Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
// Klass recreates the component mirror also // Klass recreates the component mirror also
if (_higher_dimension != NULL) {
ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
ak->restore_unshareable_info(loader_data, protection_domain, CHECK);
}
} }
// Printing // Printing

@ -130,6 +130,7 @@ class ArrayKlass: public Klass {
// CDS support - remove and restore oops from metadata. Oops are not shared. // CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info(); virtual void remove_unshareable_info();
virtual void remove_java_mirror();
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
// Printing // Printing

@ -89,8 +89,6 @@ ConstantPool::ConstantPool(Array<u1>* tags) :
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
if (cache() != NULL) { if (cache() != NULL) {
MetadataFactory::free_array<u2>(loader_data, reference_map());
set_reference_map(NULL);
MetadataFactory::free_metadata(loader_data, cache()); MetadataFactory::free_metadata(loader_data, cache());
set_cache(NULL); set_cache(NULL);
} }
@ -259,10 +257,14 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) {
} }
objArrayOop rr = resolved_references(); objArrayOop rr = resolved_references();
Array<u2>* ref_map = reference_map();
if (rr != NULL) { if (rr != NULL) {
for (int i = 0; i < rr->length(); i++) { int ref_map_len = ref_map == NULL ? 0 : ref_map->length();
int rr_len = rr->length();
for (int i = 0; i < rr_len; i++) {
oop p = rr->obj_at(i); oop p = rr->obj_at(i);
if (p != NULL) { rr->obj_at_put(i, NULL);
if (p != NULL && i < ref_map_len) {
int index = object_to_cp_index(i); int index = object_to_cp_index(i);
// Skip the entry if the string hash code is 0 since the string // Skip the entry if the string hash code is 0 since the string
// is not included in the shared string_table, see StringTable::copy_shared_string. // is not included in the shared string_table, see StringTable::copy_shared_string.
@ -273,11 +275,10 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) {
// have a 'bad' reference in the archived resolved_reference // have a 'bad' reference in the archived resolved_reference
// array. // array.
rr->obj_at_put(i, op); rr->obj_at_put(i, op);
} else {
rr->obj_at_put(i, NULL);
} }
} }
} }
oop archived = MetaspaceShared::archive_heap_object(rr, THREAD); oop archived = MetaspaceShared::archive_heap_object(rr, THREAD);
_cache->set_archived_references(archived); _cache->set_archived_references(archived);
set_resolved_references(NULL); set_resolved_references(NULL);
@ -348,6 +349,26 @@ void ConstantPool::remove_unshareable_info() {
// class redefinition. Since shared ConstantPools cannot be deallocated anyway, // class redefinition. Since shared ConstantPools cannot be deallocated anyway,
// we always set _on_stack to true to avoid having to change _flags during runtime. // we always set _on_stack to true to avoid having to change _flags during runtime.
_flags |= (_on_stack | _is_shared); _flags |= (_on_stack | _is_shared);
int num_klasses = 0;
for (int index = 1; index < length(); index++) { // Index 0 is unused
assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during dump time");
if (tag_at(index).is_klass()) {
// This class was resolved as a side effect of executing Java code
// during dump time. We need to restore it back to an UnresolvedClass,
// so that the proper class loading and initialization can happen
// at runtime.
CPKlassSlot kslot = klass_slot_at(index);
int resolved_klass_index = kslot.resolved_klass_index();
int name_index = kslot.name_index();
assert(tag_at(name_index).is_symbol(), "sanity");
resolved_klasses()->at_put(resolved_klass_index, NULL);
tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
assert(klass_name_at(index) == symbol_at(name_index), "sanity");
}
}
if (cache() != NULL) {
cache()->remove_unshareable_info();
}
} }
int ConstantPool::cp_to_object_index(int cp_index) { int ConstantPool::cp_to_object_index(int cp_index) {

@ -23,9 +23,12 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/bytecodes.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "interpreter/rewriter.hpp" #include "interpreter/rewriter.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp" #include "memory/metaspaceClosure.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp" #include "memory/universe.inline.hpp"
@ -48,6 +51,24 @@ void ConstantPoolCacheEntry::initialize_entry(int index) {
assert(constant_pool_index() == index, ""); assert(constant_pool_index() == index, "");
} }
void ConstantPoolCacheEntry::verify_just_initialized(bool f2_used) {
assert((_indices & (~cp_index_mask)) == 0, "sanity");
assert(_f1 == NULL, "sanity");
assert(_flags == 0, "sanity");
if (!f2_used) {
assert(_f2 == 0, "sanity");
}
}
void ConstantPoolCacheEntry::reinitialize(bool f2_used) {
_indices &= cp_index_mask;
_f1 = NULL;
_flags = 0;
if (!f2_used) {
_f2 = 0;
}
}
int ConstantPoolCacheEntry::make_flags(TosState state, int ConstantPoolCacheEntry::make_flags(TosState state,
int option_bits, int option_bits,
int field_index_or_method_params) { int field_index_or_method_params) {
@ -608,6 +629,74 @@ void ConstantPoolCache::initialize(const intArray& inverse_index_map,
} }
} }
void ConstantPoolCache::verify_just_initialized() {
DEBUG_ONLY(walk_entries_for_initialization(/*check_only = */ true));
}
void ConstantPoolCache::remove_unshareable_info() {
walk_entries_for_initialization(/*check_only = */ false);
}
void ConstantPoolCache::walk_entries_for_initialization(bool check_only) {
assert(DumpSharedSpaces, "sanity");
// When dumping the archive, we want to clean up the ConstantPoolCache
// to remove any effect of linking due to the execution of Java code --
// each ConstantPoolCacheEntry will have the same contents as if
// ConstantPoolCache::initialize has just returned:
//
// - We keep the ConstantPoolCache::constant_pool_index() bits for all entries.
// - We keep the "f2" field for entries used by invokedynamic and invokehandle
// - All other bits in the entries are cleared to zero.
ResourceMark rm;
InstanceKlass* ik = constant_pool()->pool_holder();
bool* f2_used = NEW_RESOURCE_ARRAY(bool, length());
memset(f2_used, 0, sizeof(bool) * length());
// Find all the slots that we need to preserve f2
for (int i = 0; i < ik->methods()->length(); i++) {
Method* m = ik->methods()->at(i);
RawBytecodeStream bcs(m);
while (!bcs.is_last_bytecode()) {
Bytecodes::Code opcode = bcs.raw_next();
switch (opcode) {
case Bytecodes::_invokedynamic: {
int index = Bytes::get_native_u4(bcs.bcp() + 1);
int cp_cache_index = constant_pool()->invokedynamic_cp_cache_index(index);
f2_used[cp_cache_index] = 1;
}
break;
case Bytecodes::_invokehandle: {
int cp_cache_index = Bytes::get_native_u2(bcs.bcp() + 1);
f2_used[cp_cache_index] = 1;
}
break;
default:
break;
}
}
}
if (check_only) {
DEBUG_ONLY(
for (int i=0; i<length(); i++) {
entry_at(i)->verify_just_initialized(f2_used[i]);
})
} else {
for (int i=0; i<length(); i++) {
entry_at(i)->reinitialize(f2_used[i]);
}
}
}
void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
assert(!is_shared(), "shared caches are not deallocated");
data->remove_handle(_resolved_references);
set_resolved_references(NULL);
MetadataFactory::free_array<u2>(data, _reference_map);
set_reference_map(NULL);
}
#if INCLUDE_CDS_JAVA_HEAP #if INCLUDE_CDS_JAVA_HEAP
oop ConstantPoolCache::archived_references() { oop ConstantPoolCache::archived_references() {
assert(UseSharedSpaces, "UseSharedSpaces expected."); assert(UseSharedSpaces, "UseSharedSpaces expected.");

@ -393,6 +393,9 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
// When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state: // When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state:
assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask"); assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask");
} }
void verify_just_initialized(bool f2_used);
void reinitialize(bool f2_used);
}; };
@ -464,7 +467,11 @@ class ConstantPoolCache: public MetaspaceObj {
// Assembly code support // Assembly code support
static int resolved_references_offset_in_bytes() { return offset_of(ConstantPoolCache, _resolved_references); } static int resolved_references_offset_in_bytes() { return offset_of(ConstantPoolCache, _resolved_references); }
// CDS support
void remove_unshareable_info();
void verify_just_initialized();
private: private:
void walk_entries_for_initialization(bool check_only);
void set_length(int length) { _length = length; } void set_length(int length) { _length = length; }
static int header_size() { return sizeof(ConstantPoolCache) / wordSize; } static int header_size() { return sizeof(ConstantPoolCache) / wordSize; }
@ -510,9 +517,9 @@ class ConstantPoolCache: public MetaspaceObj {
void dump_cache(); void dump_cache();
#endif // INCLUDE_JVMTI #endif // INCLUDE_JVMTI
// Deallocate - no fields to deallocate // RedefineClasses support
DEBUG_ONLY(bool on_stack() { return false; }) DEBUG_ONLY(bool on_stack() { return false; })
void deallocate_contents(ClassLoaderData* data) {} void deallocate_contents(ClassLoaderData* data);
bool is_klass() const { return false; } bool is_klass() const { return false; }
// Printing // Printing

@ -747,10 +747,10 @@ void InstanceKlass::initialize_impl(TRAPS) {
char* message = NEW_RESOURCE_ARRAY(char, msglen); char* message = NEW_RESOURCE_ARRAY(char, msglen);
if (NULL == message) { if (NULL == message) {
// Out of memory: can't create detailed error message // Out of memory: can't create detailed error message
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className); THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
} else { } else {
jio_snprintf(message, msglen, "%s%s", desc, className); jio_snprintf(message, msglen, "%s%s", desc, className);
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message); THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
} }
} }
@ -2067,14 +2067,14 @@ void InstanceKlass::remove_unshareable_info() {
m->remove_unshareable_info(); m->remove_unshareable_info();
} }
// do array classes also.
if (array_klasses() != NULL) {
array_klasses()->remove_unshareable_info();
}
// These are not allocated from metaspace, but they should should all be empty // These are not allocated from metaspace, but they should should all be empty
// during dump time, so we don't need to worry about them in InstanceKlass::metaspace_pointers_do(). // during dump time, so we don't need to worry about them in InstanceKlass::iterate().
guarantee(_source_debug_extension == NULL, "must be"); guarantee(_source_debug_extension == NULL, "must be");
guarantee(_oop_map_cache == NULL, "must be");
guarantee(_init_thread == NULL, "must be");
guarantee(_oop_map_cache == NULL, "must be");
guarantee(_jni_ids == NULL, "must be");
guarantee(_methods_jmethod_ids == NULL, "must be");
guarantee(_dep_context == DependencyContext::EMPTY, "must be"); guarantee(_dep_context == DependencyContext::EMPTY, "must be");
guarantee(_osr_nmethods_head == NULL, "must be"); guarantee(_osr_nmethods_head == NULL, "must be");
@ -2082,12 +2082,20 @@ void InstanceKlass::remove_unshareable_info() {
guarantee(_breakpoints == NULL, "must be"); guarantee(_breakpoints == NULL, "must be");
guarantee(_previous_versions == NULL, "must be"); guarantee(_previous_versions == NULL, "must be");
#endif #endif
_init_thread = NULL;
_methods_jmethod_ids = NULL;
_jni_ids = NULL;
_oop_map_cache = NULL;
} }
static void restore_unshareable_in_class(Klass* k, TRAPS) { void InstanceKlass::remove_java_mirror() {
// Array classes have null protection domain. Klass::remove_java_mirror();
// --> see ArrayKlass::complete_create_array_klass()
k->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK); // do array classes also.
if (array_klasses() != NULL) {
array_klasses()->remove_java_mirror();
}
} }
void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
@ -2114,7 +2122,11 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
// restore constant pool resolved references // restore constant pool resolved references
constants()->restore_unshareable_info(CHECK); constants()->restore_unshareable_info(CHECK);
array_klasses_do(restore_unshareable_in_class, CHECK); if (array_klasses() != NULL) {
// Array classes have null protection domain.
// --> see ArrayKlass::complete_create_array_klass()
array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
}
} }
// returns true IFF is_in_error_state() has been changed as a result of this call. // returns true IFF is_in_error_state() has been changed as a result of this call.

@ -327,8 +327,6 @@ class InstanceKlass: public Klass {
} }
void set_class_loader_type(s2 loader_type) { void set_class_loader_type(s2 loader_type) {
assert(( _misc_flags & loader_type_bits()) == 0,
"Should only be called once for each class.");
switch (loader_type) { switch (loader_type) {
case ClassLoader::BOOT_LOADER: case ClassLoader::BOOT_LOADER:
_misc_flags |= _misc_is_shared_boot_class; _misc_flags |= _misc_is_shared_boot_class;
@ -1335,6 +1333,7 @@ private:
public: public:
// CDS support - remove and restore oops from metadata. Oops are not shared. // CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info(); virtual void remove_unshareable_info();
virtual void remove_java_mirror();
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
// jvm support // jvm support

Some files were not shown because too many files have changed in this diff Show More